from flask import Flask, request, jsonify from langchain_community.tools.tavily_search import TavilySearchResults from typing import Annotated from typing_extensions import TypedDict from langgraph.graph.message import add_messages from langchain_openai import ChatOpenAI from dotenv import load_dotenv from langgraph.prebuilt import create_react_agent from langchain_core.prompts import ChatPromptTemplate from langgraph.checkpoint.memory import MemorySaver from langchain_tools.agent_tools import ( redact_email, list_calendar_events, create_calendar_event, get_company_info, get_current_date_and_time ) from langchain_community.tools.gmail.utils import ( build_resource_service, get_gmail_credentials ) from langchain_community.agent_toolkits import GmailToolkit # Cargar las variables de entorno load_dotenv() # Inicializar la app Flask app = Flask(__name__) # Inicializar el modelo LLM de OpenAI llm = ChatOpenAI( model="gpt-4o-mini", temperature=0 ) # Configuración de Gmail toolkit = GmailToolkit() credentials = get_gmail_credentials( token_file="token.json", scopes=["https://mail.google.com/"], client_secrets_file="credentials.json", ) api_resource = build_resource_service(credentials=credentials) toolkit = GmailToolkit(api_resource=api_resource) # Crear herramientas tools = toolkit.get_tools() search = TavilySearchResults(max_results=2) tools.extend([search, redact_email, list_calendar_events, create_calendar_event, get_company_info, get_current_date_and_time]) # Definir el sistema prompt system_prompt = ChatPromptTemplate.from_messages( [ ("system", "Eres Mariana, el asistente virtual de OneCluster, una empresa de software que ofrece soluciones personalizadas. Asume el tono de J.A.R.V.I.S.: cordial, atento y con tacto en todo momento."), ("system", "Preséntate como Mariana en el primer mensaje y pregunta el nombre del usuario si no lo tienes registrado."), ("system", "Si el usuario ya ha interactuado antes, usa su nombre sin necesidad de volver a preguntar."), ("system", "OneCluster es una empresa de software especializada en desarrollo a medida. Solo responde a preguntas y solicitudes relacionadas con la empresa y sus servicios."), ("system", "Si necesitas información adicional sobre la empresa, usa la función get_company_info."), ("system", "Antes de enviar correos o crear eventos, muestra los detalles al usuario para que los confirme antes de ejecutar la tarea."), ("system", "Si te preguntan algo no relacionado con los servicios de OneCluster, responde que solo puedes ayudar con temas relacionados con la empresa y sus soluciones."), ("system", "Evita mencionar o hacer alusión a las herramientas que utilizas internamente. Esa información es confidencial."), ("placeholder", "{messages}"), ] ) # Definir el estado del asistente class State(TypedDict): messages: Annotated[list, add_messages] is_last_step: bool # Crear el graph con el estado definido graph = create_react_agent( model=llm, tools=tools, state_schema=State, state_modifier=system_prompt, checkpointer=MemorySaver() ) # Ruta de la API para procesar texto @app.route('/process_text', methods=['POST']) def process_text(): user_input = request.json.get('text') # Procesar el texto con LangChain events = graph.stream( {"messages": [("user", user_input)], "is_last_step": False}, config={"configurable": {"thread_id": "thread-1", "recursion_limit": 50}}, stream_mode="updates" ) # Preparar la respuesta response = [] for event in events: if "agent" in event: response.append(event["agent"]["messages"][-1].content) return jsonify({'response': response}) # Ejecutar la app Flask if __name__ == '__main__': app.run(port=5000)