Files
2026-04-07 14:11:45 +08:00

177 lines
5.6 KiB
Python

# ///
# external.py
# 描述:外部扩展接口,供其他程序调用中控系统
# 作者:AI Generated
# 创建日期:2026-04-05
# ///
from fastapi import APIRouter, HTTPException, Depends
from typing import List, Optional, Dict, Any
from pydantic import BaseModel
from services.node_manager import node_manager
from plugins.base import PluginRegistry
from utils import require_external_key
router = APIRouter(prefix="/external", tags=["外部扩展接口"])
class ExternalMessageRequest(BaseModel):
node_id: str
who: str
msg: str
msg_type: str = "text"
class DataTriggerRequest(BaseModel):
node_id: str
source: str
event: str
data: Dict[str, Any]
auto_send: bool = True
target: Optional[str] = None
class PluginExecuteRequest(BaseModel):
plugin_name: str
action: str
params: Dict[str, Any] = {}
async def sync_node_from_db(node_id: str) -> bool:
from database_service import get_db_service
db_service = get_db_service()
if not db_service:
return False
node = db_service.get_node(node_id)
if not node:
return False
existing = node_manager.nodes.get(node_id)
if existing:
existing.api_url = node.api_url
existing.api_key = node.api_key
else:
await node_manager.add_node(
node_id=node.node_id,
name=node.name,
api_url=node.api_url,
api_key=node.api_key,
description=node.description or "",
group=node.group or "default"
)
return True
@router.post("/send", summary="外部接口-发送消息")
async def external_send_message(request: ExternalMessageRequest,
_=Depends(require_external_key)) -> Dict[str, Any]:
await sync_node_from_db(request.node_id)
result = await node_manager.send_message(
node_id=request.node_id,
who=request.who,
msg=request.msg,
msg_type=request.msg_type
)
return result
@router.post("/trigger", summary="外部接口-触发数据处理")
async def external_trigger(request: DataTriggerRequest,
_=Depends(require_external_key)) -> Dict[str, Any]:
plugin = PluginRegistry.get(request.source)
if not plugin:
raise HTTPException(status_code=404, detail=f"Plugin '{request.source}' not found")
if not plugin.enabled:
raise HTTPException(status_code=400, detail=f"Plugin '{request.source}' is disabled")
execute_result = plugin.execute({
"event": request.event,
"data": request.data
})
if request.auto_send and request.target:
await sync_node_from_db(request.node_id)
msg = request.data.get("message", str(request.data))
send_result = await node_manager.send_message(
node_id=request.node_id,
who=request.target,
msg=msg
)
execute_result["send_result"] = send_result
return {
"success": True,
"plugin_result": execute_result,
"data_triggered": True
}
@router.post("/plugin/execute", summary="外部接口-执行插件")
async def execute_plugin(request: PluginExecuteRequest,
_=Depends(require_external_key)) -> Dict[str, Any]:
plugin = PluginRegistry.get(request.plugin_name)
if not plugin:
raise HTTPException(status_code=404, detail=f"Plugin '{request.plugin_name}' not found")
if not plugin.enabled:
raise HTTPException(status_code=400, detail=f"Plugin '{request.plugin_name}' is disabled")
result = plugin.execute(request.params)
return {"success": True, "result": result}
@router.get("/plugins", summary="外部接口-获取可用插件列表")
async def get_plugins(_=Depends(require_external_key)) -> Dict[str, Any]:
plugins = PluginRegistry.get_all()
enabled_plugins = [p for p in plugins if p.enabled]
return {
"success": True,
"plugins": [p.get_info() for p in enabled_plugins],
"count": len(enabled_plugins)
}
@router.get("/nodes", summary="外部接口-获取可用节点")
async def get_available_nodes(_=Depends(require_external_key)) -> Dict[str, Any]:
from database_service import get_db_service
db_service = get_db_service()
if db_service:
nodes = db_service.get_enabled_nodes()
return {"success": True, "nodes": [n.to_dict() for n in nodes], "count": len(nodes)}
nodes = await node_manager.get_enabled_nodes()
return {"success": True, "nodes": [n.to_dict() for n in nodes], "count": len(nodes)}
@router.post("/ai/process", summary="外部接口-AI处理消息")
async def ai_process_message(
input_text: str,
context: Optional[Dict[str, Any]] = None,
model: Optional[str] = None,
_=Depends(require_external_key)
) -> Dict[str, Any]:
ai_plugin = PluginRegistry.get("simple_ai_agent")
if not ai_plugin or not ai_plugin.enabled:
raise HTTPException(status_code=400, detail="AI agent not available")
if model:
ai_plugin.model = model
result = ai_plugin.process(input_text, context or {})
return {"success": True, "result": result}
@router.post("/webhook/{event}", summary="外部接口-Webhook接收")
async def receive_webhook(event: str,
payload: Dict[str, Any],
_=Depends(require_external_key)) -> Dict[str, Any]:
webhook_plugin = PluginRegistry.get("webhook_trigger")
if webhook_plugin and webhook_plugin.enabled:
result = webhook_plugin.execute({
"event": event,
"data": payload
})
return {"success": True, "result": result}
return {"success": True, "message": "Webhook received", "event": event}