- 新增 Go 语言后端服务(server/),包含用户认证、Agent管理、数据库连接等API - 新增 Python Agent 服务(agent/),实现Agent核心逻辑和工具集 - 前端从原生HTML迁移到Vue.js框架(web/src/) - 添加 Docker Compose 支持(docker-compose.yml) - 添加项目架构文档(docs/ARCHITECTURE.md) - 添加环境变量示例(.env.example)和本地启动脚本(start-local.ps1) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
167 lines
4.5 KiB
Python
167 lines
4.5 KiB
Python
"""
|
||
API 调用工具 - 安全的外部 API 调用
|
||
"""
|
||
import httpx
|
||
from typing import Dict, Any, Optional
|
||
from dataclasses import dataclass
|
||
from enum import Enum
|
||
|
||
|
||
class APIPermission(Enum):
|
||
"""API 权限级别"""
|
||
PUBLIC = "public" # 公开 API
|
||
APPROVED = "approved" # 已审批的 API
|
||
ADMIN = "admin" # 管理员 API
|
||
|
||
|
||
@dataclass
|
||
class APIEndpoint:
|
||
"""API 端点定义"""
|
||
name: str
|
||
url: str
|
||
method: str
|
||
permission: APIPermission
|
||
description: str
|
||
rate_limit: int = 60 # 每分钟请求次数
|
||
|
||
|
||
# API 白名单
|
||
ALLOWED_APIS = [
|
||
APIEndpoint(
|
||
name="weather",
|
||
url="https://api.weather.example.com/v1",
|
||
method="GET",
|
||
permission=APIPermission.PUBLIC,
|
||
description="获取天气信息",
|
||
rate_limit=30
|
||
),
|
||
APIEndpoint(
|
||
name="news",
|
||
url="https://newsapi.org/v2",
|
||
method="GET",
|
||
permission=APIPermission.PUBLIC,
|
||
description="获取新闻",
|
||
rate_limit=30
|
||
),
|
||
# 可以添加更多已审批的 API
|
||
]
|
||
|
||
|
||
class APICallTool:
|
||
"""
|
||
API 调用工具
|
||
|
||
安全特性:
|
||
- 只允许调用白名单中的 API
|
||
- 速率限制
|
||
- 请求超时
|
||
- 响应大小限制
|
||
"""
|
||
|
||
def __init__(self):
|
||
self.allowed_apis = {api.name: api for api in ALLOWED_APIS}
|
||
self.request_timeout = 10 # 请求超时(秒)
|
||
self.max_response_size = 1024 * 1024 # 最大响应大小(1MB)
|
||
|
||
async def call(
|
||
self,
|
||
api_name: str,
|
||
endpoint: str = "",
|
||
params: Optional[Dict[str, Any]] = None,
|
||
headers: Optional[Dict[str, str]] = None
|
||
) -> Dict[str, Any]:
|
||
"""
|
||
调用 API
|
||
|
||
Args:
|
||
api_name: API 名称(必须在白名单中)
|
||
endpoint: 具体的端点
|
||
params: 查询参数
|
||
headers: 请求头
|
||
|
||
Returns:
|
||
API 响应
|
||
"""
|
||
# 安全检查1: API 必须在白名单中
|
||
if api_name not in self.allowed_apis:
|
||
return {
|
||
"success": False,
|
||
"error": f"API '{api_name}' not in whitelist. Allowed: {list(self.allowed_apis.keys())}"
|
||
}
|
||
|
||
api = self.allowed_apis[api_name]
|
||
|
||
# 构建完整 URL
|
||
url = f"{api.url}/{endpoint}" if endpoint else api.url
|
||
|
||
try:
|
||
async with httpx.AsyncClient(timeout=self.request_timeout) as client:
|
||
# 根据方法调用
|
||
if api.method == "GET":
|
||
response = await client.get(url, params=params, headers=headers)
|
||
elif api.method == "POST":
|
||
response = await client.post(url, json=params, headers=headers)
|
||
else:
|
||
return {
|
||
"success": False,
|
||
"error": f"Method {api.method} not supported"
|
||
}
|
||
|
||
# 检查响应大小
|
||
if len(response.content) > self.max_response_size:
|
||
return {
|
||
"success": False,
|
||
"error": f"Response too large (max {self.max_response_size} bytes)"
|
||
}
|
||
|
||
return {
|
||
"success": True,
|
||
"status_code": response.status_code,
|
||
"data": response.json() if response.headers.get("content-type", "").startswith("application/json") else response.text,
|
||
"headers": dict(response.headers)
|
||
}
|
||
|
||
except httpx.TimeoutException:
|
||
return {
|
||
"success": False,
|
||
"error": "Request timeout"
|
||
}
|
||
except Exception as e:
|
||
return {
|
||
"success": False,
|
||
"error": str(e)
|
||
}
|
||
|
||
def list_apis(self) -> list:
|
||
"""列出所有可用的 API"""
|
||
return [
|
||
{
|
||
"name": api.name,
|
||
"description": api.description,
|
||
"method": api.method,
|
||
"permission": api.permission.value,
|
||
"rate_limit": api.rate_limit
|
||
}
|
||
for api in ALLOWED_APIS
|
||
]
|
||
|
||
|
||
# 全局实例
|
||
api_tool = APICallTool()
|
||
|
||
|
||
async def call_api(
|
||
api_name: str,
|
||
endpoint: str = "",
|
||
params: Optional[Dict[str, Any]] = None
|
||
) -> Dict[str, Any]:
|
||
"""
|
||
API 调用工具(供 Agent 使用)
|
||
"""
|
||
return await api_tool.call(api_name, endpoint, params)
|
||
|
||
|
||
def list_allowed_apis() -> list:
|
||
"""列出允许的 API"""
|
||
return api_tool.list_apis()
|