// File: frontend/lib/api.ts (Update) // Description: 添加运行工作流的 API 函数 import axios from "axios"; import type { Node, Edge } from "reactflow"; // Import React Flow types import type { Assistant, Session, Message, AssistantCreateData, AssistantUpdateData, ChatApiResponse, } from "./types"; // Assuming types are defined // --- Types --- // Workflow Run types (match backend pydantic models) interface WorkflowNodeData { label?: string | null; text?: string | null; displayText?: string | null; model?: string | null; temperature?: number | null; systemPrompt?: string | null; // Add other node data fields as needed [key: string]: any; // Allow extra fields } interface WorkflowNode { id: string; type: string; position: { x: number; y: number }; data: WorkflowNodeData; } interface WorkflowEdge { id: string; source: string; target: string; sourceHandle?: string | null; targetHandle?: string | null; } interface WorkflowRunPayload { nodes: WorkflowNode[]; edges: WorkflowEdge[]; } export interface WorkflowRunResult { success: boolean; message?: string | null; output?: string | null; output_node_id?: string | null; } // --- API Client Setup --- const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000/api/v1"; const apiClient = axios.create({ baseURL: API_BASE_URL, headers: { "Content-Type": "application/json", }, }); // --- Helper for Error Handling --- const handleApiError = (error: unknown, context: string): string => { console.error(`API Error (${context}):`, error); if (axios.isAxiosError(error) && error.response) { // 尝试提取后端返回的详细错误信息 return ( error.response.data?.detail || `服务器错误 (${error.response.status})` ); } else if (error instanceof Error) { return error.message; } return "发生未知网络错误"; }; // --- Chat API --- /** * 发送聊天消息到后端 (更新) * @param message 用户消息 * @param sessionId 当前会话 ID (可以是 'temp-new-chat') * @param assistantId 当前助手 ID * @returns 包含 AI 回复和可能的新会话信息的对象 */ export const sendChatMessage = async ( message: string, sessionId: string, assistantId: string ): Promise => { try { const response = await apiClient.post("/chat/", { message, session_id: sessionId, assistant_id: assistantId, }); return response.data; // 返回整个响应体 } catch (error) { throw new Error(handleApiError(error, "sendChatMessage")); } }; // --- Assistant API --- /** 获取所有助手列表 */ export const getAssistants = async (): Promise => { try { const response = await apiClient.get("/assistants/"); return response.data; } catch (error) { throw new Error(handleApiError(error, "getAssistants")); } }; /** 创建新助手 */ export const createAssistant = async ( data: AssistantCreateData ): Promise => { try { const response = await apiClient.post("/assistants/", data); return response.data; } catch (error) { throw new Error(handleApiError(error, "createAssistant")); } }; /** 更新助手 */ export const updateAssistant = async ( id: string, data: AssistantUpdateData ): Promise => { try { const response = await apiClient.put(`/assistants/${id}`, data); return response.data; } catch (error) { throw new Error(handleApiError(error, "updateAssistant")); } }; /** 删除助手 */ export const deleteAssistant = async (id: string): Promise => { try { await apiClient.delete(`/assistants/${id}`); } catch (error) { throw new Error(handleApiError(error, "deleteAssistant")); } }; // --- Session API --- /** 获取指定助手的所有会话 */ export const getSessionsByAssistant = async ( assistantId: string ): Promise => { try { const response = await apiClient.get( `/sessions/assistant/${assistantId}` ); return response.data; } catch (error) { // 如果助手没有会话,后端可能返回 404 或空列表,这里统一处理为返回空列表 if (axios.isAxiosError(error) && error.response?.status === 404) { return []; } throw new Error(handleApiError(error, "getSessionsByAssistant")); } }; /** 删除会话 */ export const deleteSession = async (sessionId: string): Promise => { try { await apiClient.delete(`/sessions/${sessionId}`); } catch (error) { throw new Error(handleApiError(error, "deleteSession")); } }; // 注意:创建会话的 API (POST /sessions/) 在后端被整合到了 POST /chat/ 逻辑中, //当前端发送 sessionId 为 'temp-new-chat' 的消息时,后端会自动创建。 //如果需要单独创建会话(例如,不发送消息就创建),则需要单独实现前端调用 POST /sessions/。 // --- Message API (New) --- /** 获取指定会话的消息列表 */ export const getMessagesBySession = async ( sessionId: string, limit: number = 100, skip: number = 0 ): Promise => { try { const response = await apiClient.get( `/messages/session/${sessionId}`, { params: { limit, skip }, } ); return response.data; } catch (error) { // Handle 404 specifically if needed (session exists but no messages) if (axios.isAxiosError(error) && error.response?.status === 404) { return []; // Return empty list if session not found or no messages } throw new Error(handleApiError(error, "getMessagesBySession")); } }; // --- Workflow API (New) --- /** * 发送工作流定义到后端执行 * @param nodes - React Flow 节点数组 * @param edges - React Flow 边数组 * @returns 工作流执行结果 */ export const runWorkflow = async (nodes: Node[], edges: Edge[]): Promise => { // Map React Flow nodes/edges to the structure expected by the backend API const payload: WorkflowRunPayload = { nodes: nodes.map(n => ({ id: n.id, type: n.type || 'default', // Ensure type is present position: n.position, data: n.data as WorkflowNodeData, // Assume data matches for now })), edges: edges.map(e => ({ id: e.id, source: e.source, target: e.target, sourceHandle: e.sourceHandle, targetHandle: e.targetHandle, })), }; try { const response = await apiClient.post('/workflow/run', payload); return response.data; } catch (error) { // Return a failed result structure on API error return { success: false, message: handleApiError(error, 'runWorkflow'), }; } };