""" Определяет логику рабочих процессов агента, используя LangGraph для управления состояниями и переходами между узлами обработки. """ from typing import Dict, Any, Optional from langgraph.graph import StateGraph, END from graph_history_manager import GraphHistoryManager from models import AgentState from nodes import parse_command_node, execute_command_node, call_llm_node, generate_images_node, analyze_image_node, get_meet_subtitles_node, get_teams_subtitles_node, summarize_history_node, handle_error_node, help_node # --- LangGraph: Построение графа --- graph_history_manager = GraphHistoryManager() workflow = StateGraph(AgentState) # Добавляем узлы workflow.add_node("parse_command", parse_command_node) workflow.add_node("execute_command", execute_command_node) # Это по сути роутер workflow.add_node("call_llm", call_llm_node) workflow.add_node("generate_images", generate_images_node) workflow.add_node("analyze_image", analyze_image_node) workflow.add_node("get_meet_subtitles", get_meet_subtitles_node) workflow.add_node("get_teams_subtitles", get_teams_subtitles_node) workflow.add_node("summarize_history", summarize_history_node) workflow.add_node("handle_error", handle_error_node) workflow.add_node("help", help_node) # Устанавливаем точку входа workflow.set_entry_point("parse_command") # Определяем маршрутизацию после parse_command def route_command(state: AgentState) -> str: """Маршрутизирует выполнение на основе распознанной команды.""" if state.error: return "handle_error" # Если была ошибка парсинга команды elif state.command == "imagine": return "generate_images" elif state.command == "analyze": return "analyze_image" elif state.command == "subtitles_meet": return "get_meet_subtitles" elif state.command == "subtitles_teams": return "get_teams_subtitles" elif state.command == "summarize": return "summarize_history" elif state.command == "help": return "help" elif state.command == "chat": return "call_llm" elif state.command == "error": # Команда была, но не известная return "handle_error" else: # Fallback на LLM, если команда не распознана или пуста (хотя parse_command должен был бы ее поймать) return "call_llm" workflow.add_conditional_edges( "parse_command", # Откуда route_command, # Функция, определяющая куда идти { "generate_images": "generate_images", "analyze_image": "analyze_image", "get_meet_subtitles": "get_meet_subtitles", "get_teams_subtitles": "get_teams_subtitles", "summarize_history": "summarize_history", "help": "help", "call_llm": "call_llm", "handle_error": "handle_error", # Для ошибок, найденных в parse_command }, ) # Все узлы операций (кроме ошибок) ведут к END после завершения workflow.add_edge("call_llm", END) workflow.add_edge("generate_images", END) workflow.add_edge("analyze_image", END) workflow.add_edge("get_meet_subtitles", END) workflow.add_edge("get_teams_subtitles", END) workflow.add_edge("summarize_history", END) workflow.add_edge("help", END) workflow.add_edge("handle_error", END) # Ошибка - это тоже конечный пункт для текущего запроса # Компилируем граф app = workflow.compile() def run_agent(user_input: str, existing_graph_id: Optional[str] = None, parent_node_id: Optional[str] = None) -> Dict[str, Any]: """ Запускает агента с заданным пользовательским вводом. Может продолжить существующий граф по graph_id. Возвращает обновленное состояние и ID графа. """ initial_state = AgentState(input=user_input, parent_node_id=parent_node_id) # Если есть существующий ID графа, загружаем его историю if existing_graph_id: existing_graph_data = graph_history_manager.get_graph( existing_graph_id) if existing_graph_data: print(f"Продолжаю существующий граф {existing_graph_id}") initial_state.chat_history = existing_graph_data.get( "messages", []) initial_state.graph_nodes = existing_graph_data.get( "graph_nodes", []) initial_state.graph_edges = existing_graph_data.get( "graph_edges", []) initial_state.parent_node_id = parent_node_id or existing_graph_data.get( "current_node_id") # Запускаем граф result = app.invoke(initial_state) final_state = AgentState(**result) # Сохраняем обновленное состояние графа graph_data_to_save = { "id": existing_graph_id, "messages": final_state.chat_history, "graph_nodes": final_state.graph_nodes, "graph_edges": final_state.graph_edges, "current_node_id": final_state.current_node_id } new_graph_id = graph_history_manager.save_graph(graph_data_to_save) # Формируем ответ для фронтенда response_data = { "graph_id": new_graph_id, "messages": final_state.chat_history, "llm_response": final_state.llm_response, "image_urls": final_state.image_urls, "analysis_result": final_state.analysis_result, "subtitles": final_state.subtitles, "summarized_history_text": final_state.summarized_history_text, "error": final_state.error, "graph_visualization_data": { "nodes": final_state.graph_nodes, "edges": final_state.graph_edges, "current_node_id": final_state.current_node_id } } return response_data