# /// # 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}