Compare commits
	
		
			3 Commits
		
	
	
		
			9e94bafb81
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 03183457c6 | ||
|  | 283da64cd3 | ||
|  | 86b3fc8d0e | 
| @@ -1,12 +1,15 @@ | ||||
| FROM python:3.11-slim | ||||
|  | ||||
| RUN pip install poetry==1.6.1 | ||||
| RUN pip install poetry==1.8.4 | ||||
|  | ||||
| RUN poetry config virtualenvs.create false | ||||
|  | ||||
| WORKDIR /code | ||||
|  | ||||
| COPY ./pyproject.toml ./README.md ./poetry.lock* ./ | ||||
| COPY ./pyproject.toml ./README.md ./ | ||||
|  | ||||
| # Generar el archivo lock desde cero | ||||
| RUN poetry lock --no-update | ||||
|  | ||||
| COPY ./package[s] ./packages | ||||
|  | ||||
|   | ||||
| @@ -1 +0,0 @@ | ||||
| {"installed":{"client_id":"19011937557-bi5nh4afvg4tuqr87v6dp55qj9a9o1h2.apps.googleusercontent.com","project_id":"oc-aassistent","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"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","redirect_uris":["http://localhost"]}} | ||||
| @@ -1 +0,0 @@ | ||||
| {"installed":{"client_id":"629922809906-pl9l1ipout6d5hh19ku50sfvnqgu8ir2.apps.googleusercontent.com","project_id":"calendar-424503","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"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","redirect_uris":["http://localhost"]}} | ||||
| @@ -2,15 +2,12 @@ from dotenv import load_dotenv | ||||
| from langchain_openai import ChatOpenAI | ||||
| from langchain_core.tools import tool | ||||
| from datetime import datetime, timezone | ||||
| from google.oauth2.credentials import Credentials | ||||
| from google_auth_oauthlib.flow import InstalledAppFlow | ||||
| from google.auth.transport.requests import Request | ||||
| from googleapiclient.discovery import build | ||||
| from app.rag.split_docs import load_split_docs | ||||
| from app.rag.llm import load_llm_openai | ||||
| from app.rag.embeddings import load_embeddins | ||||
| from app.rag.retriever import create_retriever | ||||
| from app.rag.vectorstore import create_verctorstore | ||||
| from app.rag.vectorstore import create_vectorstore | ||||
| from app.rag.rag_chain import create_rag_chain | ||||
| import pytz | ||||
| import telebot | ||||
| @@ -32,12 +29,6 @@ class LangChainTools: | ||||
|         return llm | ||||
|  | ||||
|  | ||||
| @tool | ||||
| def multiply(first_int: int, second_int: int) -> int: | ||||
|     """Multiply two integers together.""" | ||||
|     return first_int * second_int | ||||
|  | ||||
|  | ||||
| @tool | ||||
| def redact_email(topic: str) -> str: | ||||
|     """Use this tool to draft the content of an email based on a topic.""" | ||||
| @@ -57,232 +48,6 @@ def redact_email(topic: str) -> str: | ||||
|     return response | ||||
|  | ||||
|  | ||||
| @tool | ||||
| def list_calendar_events(max_results: int = 50) -> list: | ||||
|     """Use this tool to list upcoming calendar events.""" | ||||
|  | ||||
|     # Define los alcances que necesitamos para acceder a | ||||
|     # la API de Google Calendar | ||||
|     SCOPES = ['https://www.googleapis.com/auth/calendar'] | ||||
|  | ||||
|     creds = None | ||||
|  | ||||
|     # La ruta al archivo token.json, que contiene | ||||
|     # los tokens de acceso y actualización | ||||
|     token_path = 'token.json' | ||||
|  | ||||
|     # La ruta al archivo de credenciales de OAuth 2.1 | ||||
|     creds_path = 'credentials.json' | ||||
|  | ||||
|     # Cargar las credenciales desde el archivo token.json, si existe | ||||
|     if os.path.exists(token_path): | ||||
|         creds = Credentials.from_authorized_user_file(token_path, SCOPES) | ||||
|  | ||||
|     # Si no hay credenciales válidas disponibles, inicia el flujo de OAuth 2.0 | ||||
|     # para obtener nuevas credenciales | ||||
|     if not creds or not creds.valid: | ||||
|         if creds and creds.expired and creds.refresh_token: | ||||
|             creds.refresh(Request()) | ||||
|         else: | ||||
|             flow = InstalledAppFlow.from_client_secrets_file( | ||||
|                 creds_path, SCOPES) | ||||
|             creds = flow.run_local_server(port=0) | ||||
|  | ||||
|         # Guarda las credenciales para la próxima ejecución | ||||
|         with open(token_path, 'w') as token_file: | ||||
|             token_file.write(creds.to_json()) | ||||
|  | ||||
|     # Construye el objeto de servicio para interactuar | ||||
|     # con la API de Google Calendar | ||||
|     service = build('calendar', 'v3', credentials=creds) | ||||
|  | ||||
|     # Identificador del calendario que deseas consultar. | ||||
|     # 'primary' se refiere al calendario principal del usuario. | ||||
|     calendar_id = 'primary' | ||||
|  | ||||
|     # Realiza una llamada a la API para obtener una lista de eventos. | ||||
|     now = datetime.now(timezone.utc).isoformat()  # 'Z' indica UTC | ||||
|     events_result = service.events().list( | ||||
|         calendarId=calendar_id, timeMin=now, | ||||
|         maxResults=max_results, singleEvents=True, | ||||
|         orderBy='startTime').execute() | ||||
|  | ||||
|     # Extrae los eventos de la respuesta de la API. | ||||
|     events = events_result.get('items', []) | ||||
|  | ||||
|     # Si no se encuentran eventos, imprime un mensaje. | ||||
|     if not events: | ||||
|         print('No upcoming events found.') | ||||
|         return | ||||
|  | ||||
|     # Recorre la lista de eventos y muestra la hora de inicio | ||||
|     # y el resumen de cada evento. | ||||
|     for event in events: | ||||
|         # Obtiene la fecha y hora de inicio del evento. | ||||
|         # Puede ser 'dateTime' o 'date'. | ||||
|         start = event['start'].get('dateTime', event['start'].get('date')) | ||||
|         # Imprime la hora de inicio y el resumen (título) del evento. | ||||
|         print(start, event['summary']) | ||||
|  | ||||
|     return events | ||||
|  | ||||
|  | ||||
| @tool | ||||
| def create_calendar_event( | ||||
|         title: str, start_time: datetime, | ||||
|         end_time: datetime, attendees: list) -> dict: | ||||
|     """Use this tool to create an event in the calendar. | ||||
|  | ||||
|     Parameters: | ||||
|     - title: str - The title of the event. | ||||
|     - start_time: datetime - The start time of the event. | ||||
|     - end_time: datetime - The end time of the event. | ||||
|     - attendees: list - A list of attendee emails (required). | ||||
|  | ||||
|     Returns: | ||||
|     - dict - The created event details. | ||||
|     """ | ||||
|  | ||||
|     if not attendees: | ||||
|         raise ValueError( | ||||
|             "El campo 'attendees' es obligatorio y no puede estar vacío.") | ||||
|  | ||||
|     SCOPES = ['https://www.googleapis.com/auth/calendar'] | ||||
|     creds = None | ||||
|  | ||||
|     # La ruta al archivo token.json, | ||||
|     # que contiene los tokens de acceso y actualización | ||||
|     token_path = 'token_2.json' | ||||
|  | ||||
|     # La ruta al archivo de credenciales de OAuth 2.0 | ||||
|     creds_path = 'credentials_2.json' | ||||
|  | ||||
|     # Cargar las credenciales desde el archivo token.json, si existe | ||||
|     if os.path.exists(token_path): | ||||
|         creds = Credentials.from_authorized_user_file(token_path, SCOPES) | ||||
|  | ||||
|     # Si no hay credenciales válidas disponibles, | ||||
|     # inicia el flujo de OAuth 2.0 para obtener nuevas credenciales | ||||
|     if not creds or not creds.valid: | ||||
|         if creds and creds.expired and creds.refresh_token: | ||||
|             creds.refresh(Request()) | ||||
|         else: | ||||
|             flow = InstalledAppFlow.from_client_secrets_file( | ||||
|                 creds_path, SCOPES) | ||||
|             creds = flow.run_local_server(port=0) | ||||
|  | ||||
|         # Guarda las credenciales para la próxima ejecución | ||||
|         with open(token_path, 'w') as token_file: | ||||
|             token_file.write(creds.to_json()) | ||||
|  | ||||
|     # Construye el objeto de servicio para | ||||
|     # interactuar con la API de Google Calendar | ||||
|     service = build('calendar', 'v3', credentials=creds) | ||||
|  | ||||
|     # Validar y filtrar asistentes | ||||
|     valid_attendees = [] | ||||
|     for email in attendees: | ||||
|         if isinstance(email, str) and '@' in email: | ||||
|             valid_attendees.append({'email': email}) | ||||
|         else: | ||||
|             raise ValueError(f"'{email}' no es un correo electrónico válido.") | ||||
|  | ||||
|     # Identificador del calendario que deseas modificar. | ||||
|     # 'primary' se refiere al calendario principal del usuario. | ||||
|     calendar_id = 'primary' | ||||
|  | ||||
|     # Define el cuerpo del evento con el título, | ||||
|     # la hora de inicio y la hora de finalización | ||||
|     event = { | ||||
|         'summary': title, | ||||
|         'start': { | ||||
|             'dateTime': start_time.strftime('%Y-%m-%dT%H:%M:%S'), | ||||
|             'timeZone': 'America/Bogota', | ||||
|         }, | ||||
|         'end': { | ||||
|             'dateTime': end_time.strftime('%Y-%m-%dT%H:%M:%S'), | ||||
|             'timeZone': 'America/Bogota', | ||||
|         }, | ||||
|         'attendees': valid_attendees | ||||
|     } | ||||
|  | ||||
|     try: | ||||
|         # Crea el evento en el calendario | ||||
|         event = service.events().insert( | ||||
|             calendarId=calendar_id, body=event).execute() | ||||
|         print('Event created: %s' % (event.get('htmlLink'))) | ||||
|     except Exception as e: | ||||
|         print(f"Error al crear el evento: {e}") | ||||
|         return {} | ||||
|  | ||||
|     return event | ||||
|  | ||||
|  | ||||
| @tool | ||||
| def create_quick_add_event(quick_add_text: str): | ||||
|     """ | ||||
|     Use this tool to create events in the calendar from natural language, | ||||
|     using the Quick Add feature of Google Calendar. | ||||
|     """ | ||||
|     quick_add_text: str = input( | ||||
|         "- Escribe la descripcion del evento que quieres crear: ") | ||||
|     SCOPES = ['https://www.googleapis.com/auth/calendar'] | ||||
|  | ||||
|     creds = None | ||||
|  | ||||
|     # La ruta al archivo token.json, | ||||
|     # que contiene los tokens de acceso y actualización | ||||
|     token_path = 'token_2.json' | ||||
|  | ||||
|     # La ruta al archivo de credenciales de OAuth 2.0 | ||||
|     creds_path = 'credentials_2.json' | ||||
|  | ||||
|     # Cargar las credenciales desde el archivo token.json, si existe | ||||
|     if os.path.exists(token_path): | ||||
|         creds = Credentials.from_authorized_user_file(token_path, SCOPES) | ||||
|  | ||||
|     # Si no hay credenciales válidas disponibles, | ||||
|     # inicia el flujo de OAuth 2.0 para obtener nuevas credenciales | ||||
|     if not creds or not creds.valid: | ||||
|         if creds and creds.expired and creds.refresh_token: | ||||
|             creds.refresh(Request()) | ||||
|         else: | ||||
|             flow = InstalledAppFlow.from_client_secrets_file( | ||||
|                 creds_path, SCOPES) | ||||
|             creds = flow.run_local_server(port=0) | ||||
|  | ||||
|         # Guarda las credenciales para la próxima ejecución | ||||
|         with open(token_path, 'w') as token_file: | ||||
|             token_file.write(creds.to_json()) | ||||
|  | ||||
|     # Construye el objeto de servicio para interactuar | ||||
|     # con la API de Google Calendar | ||||
|     service = build('calendar', 'v3', credentials=creds) | ||||
|  | ||||
|     # Identificador del calendario que deseas modificar. | ||||
|     # 'primary' se refiere al calendario principal del usuario. | ||||
|     calendar_id = 'primary' | ||||
|  | ||||
|     # Crea el evento utilizando la funcionalidad Quick Add | ||||
|     event = service.events().quickAdd( | ||||
|         calendarId=calendar_id, text=quick_add_text).execute() | ||||
|  | ||||
|     print('Event created: %s' % (event.get('htmlLink'))) | ||||
|  | ||||
|     return event | ||||
|  | ||||
|  | ||||
| # @tool | ||||
| # def send_message(message: str): | ||||
| #     """Use this function when you need to communicate with the user.""" | ||||
| #     # Configuración del bot | ||||
| #     load_dotenv() | ||||
| #     API_TOKEN_BOT = os.getenv("API_TOKEN_BOT") | ||||
| #     bot = telebot.TeleBot(API_TOKEN_BOT) | ||||
| # | ||||
| #     bot.send_message(chat_id="5076346205", text=message) | ||||
| # | ||||
|  | ||||
| @tool | ||||
| def send_message(message: str): | ||||
|     """Use this function when you need to communicate with Cristian.""" | ||||
| @@ -293,6 +58,7 @@ def send_message(message: str): | ||||
|  | ||||
|     # Escapar caracteres especiales en Markdown | ||||
|     from telebot.util import escape_markdown | ||||
|  | ||||
|     safe_message = escape_markdown(message) | ||||
|  | ||||
|     # Enviar mensaje usando MarkdownV2 | ||||
| @@ -306,31 +72,27 @@ def get_company_info(prompt: str) -> str: | ||||
|     Use this function when you need more information | ||||
|     about the services offered by OneCluster. | ||||
|     """ | ||||
|     file_path: str = 'onecluster_info.pdf' | ||||
|     file_path: str = "onecluster_info.pdf" | ||||
|  | ||||
|     docs_split: list = load_split_docs(file_path) | ||||
|     embeddings_model = load_embeddins() | ||||
|     llm = load_llm_openai() | ||||
|     create_verctorstore( | ||||
|         docs_split, | ||||
|         embeddings_model, | ||||
|         file_path | ||||
|     ) | ||||
|     retriever = create_retriever( | ||||
|         embeddings_model, | ||||
|         persist_directory="embeddings/onecluster_info" | ||||
|     ) | ||||
|     qa = create_rag_chain( | ||||
|         llm, retriever) | ||||
|     try: | ||||
|         docs_split: list = load_split_docs(file_path) | ||||
|         embeddings_model = load_embeddins() | ||||
|         llm = load_llm_openai() | ||||
|  | ||||
|     # prompt: str = "Escribe un parrarfo describiendo cuantos son y | ||||
|     # cuales son los servicios que ofrece OneCluster | ||||
|     # y brinda detalles sobre cada uno." | ||||
|     response = qa.invoke( | ||||
|         {"input": prompt, "chat_history": []} | ||||
|     ) | ||||
|         # Usar el nombre corregido de la función | ||||
|         create_vectorstore(docs_split, embeddings_model, file_path) | ||||
|  | ||||
|     return response["answer"] | ||||
|         retriever = create_retriever( | ||||
|             embeddings_model, persist_directory="embeddings/onecluster_info" | ||||
|         ) | ||||
|         qa = create_rag_chain(llm, retriever) | ||||
|  | ||||
|         response = qa.invoke({"input": prompt, "chat_history": []}) | ||||
|  | ||||
|         return response["answer"] | ||||
|     except Exception as e: | ||||
|         print(f"Error en get_company_info: {e}") | ||||
|         return f"Lo siento, hubo un error al procesar la información: {str(e)}" | ||||
|  | ||||
|  | ||||
| @tool | ||||
| @@ -341,6 +103,6 @@ def get_current_date_and_time(): | ||||
|     Returns: | ||||
|         str: Current date and time in Bogotá, Colombia. | ||||
|     """ | ||||
|     bogota_tz = pytz.timezone('America/Bogota') | ||||
|     bogota_tz = pytz.timezone("America/Bogota") | ||||
|     current_date_and_time = datetime.now(bogota_tz) | ||||
|     return current_date_and_time.strftime('%Y-%m-%d %H:%M:%S') | ||||
|     return current_date_and_time.strftime("%Y-%m-%d %H:%M:%S") | ||||
|   | ||||
| @@ -2,16 +2,18 @@ from langchain_chroma import Chroma | ||||
| import os | ||||
|  | ||||
|  | ||||
| def create_verctorstore(docs_split: list, embeddings, file_name: str): | ||||
| def create_vectorstore(docs_split: list, embeddings, file_name: str): | ||||
|     db_name: str = file_name.replace(".pdf", "").replace(" ", "_").lower() | ||||
|  | ||||
|     persist_directory: str = f"embeddings/{db_name}" | ||||
|  | ||||
|     if not os.path.exists(persist_directory): | ||||
|         vectordb = Chroma.from_documents( | ||||
|             persist_directory=persist_directory, | ||||
|             documents=docs_split, | ||||
|             embedding=embeddings, | ||||
|         ) | ||||
|     # Crear el directorio si no existe | ||||
|     os.makedirs(persist_directory, exist_ok=True) | ||||
|  | ||||
|         return vectordb | ||||
|     # Siempre crear/actualizar el vectorstore | ||||
|     vectordb = Chroma.from_documents( | ||||
|         persist_directory=persist_directory, | ||||
|         documents=docs_split, | ||||
|         embedding=embeddings, | ||||
|     ) | ||||
|  | ||||
|     return vectordb | ||||
|   | ||||
							
								
								
									
										158
									
								
								app/server.py
									
									
									
									
									
								
							
							
						
						
									
										158
									
								
								app/server.py
									
									
									
									
									
								
							| @@ -6,17 +6,13 @@ from langserve import add_routes | ||||
| from langchain_core.prompts import ChatPromptTemplate | ||||
|  | ||||
| from langchain_community.tools.tavily_search import TavilySearchResults | ||||
| from langchain_community.tools.gmail.utils import ( | ||||
|     build_resource_service, | ||||
|     get_gmail_credentials) | ||||
| from langchain_community.tools.gmail.utils import build_resource_service | ||||
| from langchain_community.agent_toolkits import GmailToolkit | ||||
|  | ||||
| from app.langchain_tools.agent_tools import ( | ||||
|     redact_email, | ||||
|     list_calendar_events, | ||||
|     create_calendar_event, | ||||
|     get_company_info, | ||||
|     get_current_date_and_time | ||||
|     get_current_date_and_time, | ||||
| ) | ||||
|  | ||||
| from langgraph.graph.message import add_messages | ||||
| @@ -26,33 +22,24 @@ from langgraph.checkpoint.memory import MemorySaver | ||||
| from typing import Annotated | ||||
| from typing_extensions import TypedDict | ||||
| from dotenv import load_dotenv | ||||
| import os | ||||
|  | ||||
| load_dotenv() | ||||
|  | ||||
| app = FastAPI() | ||||
| llm = ChatOpenAI( | ||||
|     model="gpt-4o-mini", | ||||
|     temperature=0.9 | ||||
| ) | ||||
| llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.9) | ||||
|  | ||||
|  | ||||
| # # 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() | ||||
| 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]) | ||||
| tools.extend( | ||||
|     [ | ||||
|         search, | ||||
|         get_company_info, | ||||
|         get_current_date_and_time, | ||||
|     ] | ||||
| ) | ||||
|  | ||||
| # # Definir el sistema prompt | ||||
| system_prompt = ChatPromptTemplate.from_messages( | ||||
| @@ -61,42 +48,49 @@ 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." | ||||
|             "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", | ||||
|             "Si el primer mensaje del usuario es una solicitud, pregúntale su " | ||||
|             "nombre antes de responder si aún no lo conoces.", | ||||
|         ), | ||||
|         ( | ||||
|             "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", | ||||
|          "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", | ||||
|          "Si el primer mensaje del usuario es una solicitud, pregúntale su " | ||||
|          "nombre antes de responder si aún no lo conoces." | ||||
|          ), | ||||
|         ("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." | ||||
|             "internamente. Esa información es confidencial.", | ||||
|         ), | ||||
|         ("placeholder", "{messages}"), | ||||
|     ] | ||||
| @@ -115,7 +109,7 @@ graph = create_react_agent( | ||||
|     tools=tools, | ||||
|     state_schema=State, | ||||
|     state_modifier=system_prompt, | ||||
|     checkpointer=MemorySaver() | ||||
|     checkpointer=MemorySaver(), | ||||
| ) | ||||
|  | ||||
|  | ||||
| @@ -125,11 +119,7 @@ async def redirect_root_to_docs(): | ||||
|  | ||||
|  | ||||
| # # Edit this to add the chain you want to add | ||||
| add_routes( | ||||
|     app, | ||||
|     llm, | ||||
|     path="/openai" | ||||
| ) | ||||
| add_routes(app, llm, path="/openai") | ||||
|  | ||||
|  | ||||
| @app.post("/process_text") | ||||
| @@ -140,9 +130,8 @@ async def process_text(request: Request): | ||||
|     # 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" | ||||
|         config={"configurable": {"thread_id": "thread-1", "recursion_limit": 50}}, | ||||
|         stream_mode="updates", | ||||
|     ) | ||||
|  | ||||
|     # Preparar la respuesta | ||||
| @@ -151,24 +140,33 @@ async def process_text(request: Request): | ||||
|         if "agent" in event: | ||||
|             response.append(event["agent"]["messages"][-1].content) | ||||
|  | ||||
|     return JSONResponse(content={'response': response}) | ||||
|     return JSONResponse(content={"response": response}) | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     config = {"configurable": {"thread_id": "thread-1", "recursion_limit": 50}} | ||||
|  | ||||
|     while True: | ||||
|         user_input = input("User: ") | ||||
|         if user_input.lower() in ["quit", "exit", "q"]: | ||||
|             print("Goodbye!") | ||||
|             break | ||||
|     # Modo interactivo por defecto | ||||
|     import sys | ||||
|  | ||||
|         events = graph.stream({ | ||||
|             "messages": [("user", user_input)], | ||||
|             "is_last_step": False}, | ||||
|                               config, stream_mode="updates") | ||||
|     if "--server" not in sys.argv: | ||||
|         while True: | ||||
|             user_input = input("User: ") | ||||
|             if user_input.lower() in ["quit", "exit", "q"]: | ||||
|                 print("Goodbye!") | ||||
|                 break | ||||
|  | ||||
|         for event in events: | ||||
|             if "agent" in event: | ||||
|                 print( | ||||
|                     f"\nAsistente: {event['agent']['messages'][-1].content}\n") | ||||
|             events = graph.stream( | ||||
|                 {"messages": [("user", user_input)], "is_last_step": False}, | ||||
|                 config, | ||||
|                 stream_mode="updates", | ||||
|             ) | ||||
|  | ||||
|             for event in events: | ||||
|                 if "agent" in event: | ||||
|                     print(f"\nAsistente: {event['agent']['messages'][-1].content}\n") | ||||
|     else: | ||||
|         # Modo servidor con uvicorn | ||||
|         import uvicorn | ||||
|  | ||||
|         uvicorn.run(app, host="0.0.0.0", port=8080) | ||||
|   | ||||
| @@ -1,27 +0,0 @@ | ||||
| from fastapi.testclient import TestClient | ||||
| from app.server import app  # Asegúrate de importar tu aplicación FastAPI | ||||
|  | ||||
| # Crea un cliente de prueba | ||||
| client = TestClient(app) | ||||
|  | ||||
|  | ||||
| def test_process_text(): | ||||
|     # Define el texto de entrada | ||||
|     input_text = {"text": "Hola, ¿cómo estás?"} | ||||
|  | ||||
|     # Realiza una solicitud POST al endpoint | ||||
|     response = client.post("/process_text", json=input_text) | ||||
|  | ||||
|     # Verifica que la respuesta tenga un código de estado 200 | ||||
|     assert response.status_code == 200 | ||||
|  | ||||
|     # Verifica que la respuesta contenga la clave 'response' | ||||
|     assert 'response' in response.json() | ||||
|  | ||||
|     # Verifica que la respuesta sea una lista | ||||
|     assert isinstance(response.json()['response'], list) | ||||
|  | ||||
|     # Aquí puedes agregar más verificaciones | ||||
|     # según lo que esperas en la respuesta | ||||
|     # Por ejemplo, verificar que la lista no esté vacía | ||||
|     assert len(response.json()['response']) > 0 | ||||
| @@ -1 +0,0 @@ | ||||
| {"token": "ya29.a0AeDClZCbHA_Ubcy6IrJJZgcHOb95xrUDMIjoNryaK6DaV7RH93INeBAeKIAfaDw73grkGnBD2Ub2QuvqvRMJO6DvivonA6yoLj7hFvDgSLsfNXo5xcLJqsgiIiOfExr74m4WcT5jnpZswxk3ZuEtAoXuPDW7hzLXnTwk6sFDmAaCgYKAeoSARASFQHGX2MiPDgm1tQCv4YbN3Bq9f4zvg0177", "refresh_token": "1//05Hc2PufwLWe2CgYIARAAGAUSNwF-L9IrU2s--kkp6Q2fCzN5uf2vLBvEcYHyJOFZjCQAUpBSC0FWiCUg9wgm8cCMccEGe4Q7MPg", "token_uri": "https://oauth2.googleapis.com/token", "client_id": "19011937557-bi5nh4afvg4tuqr87v6dp55qj9a9o1h2.apps.googleusercontent.com", "client_secret": "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", "scopes": ["https://mail.google.com/"], "universe_domain": "googleapis.com", "account": "", "expiry": "2024-11-07T23:37:58.891983Z"} | ||||
| @@ -1 +0,0 @@ | ||||
| {"token": "ya29.a0AeDClZC30_gM1YE3u8XHKpmLqIcABYBZzJOVQfrNyUJrFuOPxNpt96IbTeCIM266Es--v34aMA70oZG1GIELbcuExSSQ25_pzdHd9yS18vDOgdz8OtuG24_2DGnaCy7FOQBZzFr5GxgLJ_657Zal3RF8lreEFLyVLKdGf6TiaCgYKATMSARASFQHGX2MiirXKmKxKPjAWuSG0af_xmw0175", "refresh_token": "1//05akITlwASya5CgYIARAAGAUSNwF-L9IryPh1Y647Eim5KZZhD3DKCuUtkAp28N30ed1TALtax5TkflyKGxDtBmayKowuMZkaT9k", "token_uri": "https://oauth2.googleapis.com/token", "client_id": "629922809906-pl9l1ipout6d5hh19ku50sfvnqgu8ir2.apps.googleusercontent.com", "client_secret": "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", "scopes": ["https://www.googleapis.com/auth/calendar"], "universe_domain": "googleapis.com", "account": "", "expiry": "2024-11-02T23:47:30.521929Z"} | ||||
| @@ -1 +0,0 @@ | ||||
| {"installed":{"client_id":"19011937557-bi5nh4afvg4tuqr87v6dp55qj9a9o1h2.apps.googleusercontent.com","project_id":"oc-aassistent","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"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","redirect_uris":["http://localhost"]}} | ||||
| @@ -1 +0,0 @@ | ||||
| {"installed":{"client_id":"629922809906-pl9l1ipout6d5hh19ku50sfvnqgu8ir2.apps.googleusercontent.com","project_id":"calendar-424503","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"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","redirect_uris":["http://localhost"]}} | ||||
| @@ -13,8 +13,11 @@ services: | ||||
|       - "8080:8080" | ||||
|     volumes: | ||||
|       - .:/code | ||||
|       - ./google_credentials.json:/code/google_credentials.json | ||||
|       - ./tokens:/code/tokens | ||||
|     environment: | ||||
|       - PYTHONUNBUFFERED=1 | ||||
|       - GOOGLE_APPLICATION_CREDENTIALS=/code/google_credentials.json | ||||
|     command: > | ||||
|       uvicorn app.server:app --host 0.0.0.0 --port 8080 | ||||
|     env_file: | ||||
|   | ||||
							
								
								
									
										4322
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4322
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -9,18 +9,20 @@ packages = [ | ||||
| ] | ||||
|  | ||||
| [tool.poetry.dependencies] | ||||
| python = "^3.11" | ||||
| python = "^3.9" | ||||
| uvicorn = "^0.23.2" | ||||
| langserve = {extras = ["server"], version = ">=0.0.30"} | ||||
| pydantic = "<3" | ||||
| langgraph = "^0.2.28" | ||||
| langchain-community = "^0.3.1" | ||||
| langchain = "^0.3.8" | ||||
| langchain-community = "^0.3.8" | ||||
| langchain-openai = "^0.2.5" | ||||
| langchain-chroma = "^0.1.4" | ||||
| google = "^3.0.0" | ||||
| google-auth = "^2.35.0" | ||||
| google-auth-oauthlib = "^1.2.0" | ||||
| google-api-python-client = "^2.131.0" | ||||
| google-auth-oauthlib = "^1.1.0" | ||||
| google-auth-httplib2 = "^0.1.0" | ||||
| google-api-python-client = "^2.108.0" | ||||
| flake8 = "^7.1.1" | ||||
| httpx = "^0.27.2" | ||||
| pytest = "^8.3.3" | ||||
| @@ -31,8 +33,6 @@ pytz = "^2024.2" | ||||
| telebot = "^0.0.5" | ||||
| pypdf = "^5.1.0" | ||||
|  | ||||
|  | ||||
|  | ||||
| [tool.poetry.group.dev.dependencies] | ||||
| langchain-cli = ">=0.0.15" | ||||
|  | ||||
|   | ||||
| @@ -1 +0,0 @@ | ||||
| {"token": "ya29.a0AeDClZCbHA_Ubcy6IrJJZgcHOb95xrUDMIjoNryaK6DaV7RH93INeBAeKIAfaDw73grkGnBD2Ub2QuvqvRMJO6DvivonA6yoLj7hFvDgSLsfNXo5xcLJqsgiIiOfExr74m4WcT5jnpZswxk3ZuEtAoXuPDW7hzLXnTwk6sFDmAaCgYKAeoSARASFQHGX2MiPDgm1tQCv4YbN3Bq9f4zvg0177", "refresh_token": "1//05Hc2PufwLWe2CgYIARAAGAUSNwF-L9IrU2s--kkp6Q2fCzN5uf2vLBvEcYHyJOFZjCQAUpBSC0FWiCUg9wgm8cCMccEGe4Q7MPg", "token_uri": "https://oauth2.googleapis.com/token", "client_id": "19011937557-bi5nh4afvg4tuqr87v6dp55qj9a9o1h2.apps.googleusercontent.com", "client_secret": "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", "scopes": ["https://mail.google.com/"], "universe_domain": "googleapis.com", "account": "", "expiry": "2024-11-07T23:37:58.891983Z"} | ||||
| @@ -1 +0,0 @@ | ||||
| {"token": "ya29.a0AeDClZC30_gM1YE3u8XHKpmLqIcABYBZzJOVQfrNyUJrFuOPxNpt96IbTeCIM266Es--v34aMA70oZG1GIELbcuExSSQ25_pzdHd9yS18vDOgdz8OtuG24_2DGnaCy7FOQBZzFr5GxgLJ_657Zal3RF8lreEFLyVLKdGf6TiaCgYKATMSARASFQHGX2MiirXKmKxKPjAWuSG0af_xmw0175", "refresh_token": "1//05akITlwASya5CgYIARAAGAUSNwF-L9IryPh1Y647Eim5KZZhD3DKCuUtkAp28N30ed1TALtax5TkflyKGxDtBmayKowuMZkaT9k", "token_uri": "https://oauth2.googleapis.com/token", "client_id": "629922809906-pl9l1ipout6d5hh19ku50sfvnqgu8ir2.apps.googleusercontent.com", "client_secret": "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", "scopes": ["https://www.googleapis.com/auth/calendar"], "universe_domain": "googleapis.com", "account": "", "expiry": "2024-11-02T23:47:30.521929Z"} | ||||
		Reference in New Issue
	
	Block a user