Compare commits
3 Commits
9e94bafb81
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03183457c6 | ||
|
|
283da64cd3 | ||
|
|
86b3fc8d0e |
@@ -1,12 +1,15 @@
|
|||||||
FROM python:3.11-slim
|
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
|
RUN poetry config virtualenvs.create false
|
||||||
|
|
||||||
WORKDIR /code
|
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
|
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_openai import ChatOpenAI
|
||||||
from langchain_core.tools import tool
|
from langchain_core.tools import tool
|
||||||
from datetime import datetime, timezone
|
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 googleapiclient.discovery import build
|
||||||
from app.rag.split_docs import load_split_docs
|
from app.rag.split_docs import load_split_docs
|
||||||
from app.rag.llm import load_llm_openai
|
from app.rag.llm import load_llm_openai
|
||||||
from app.rag.embeddings import load_embeddins
|
from app.rag.embeddings import load_embeddins
|
||||||
from app.rag.retriever import create_retriever
|
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
|
from app.rag.rag_chain import create_rag_chain
|
||||||
import pytz
|
import pytz
|
||||||
import telebot
|
import telebot
|
||||||
@@ -32,12 +29,6 @@ class LangChainTools:
|
|||||||
return llm
|
return llm
|
||||||
|
|
||||||
|
|
||||||
@tool
|
|
||||||
def multiply(first_int: int, second_int: int) -> int:
|
|
||||||
"""Multiply two integers together."""
|
|
||||||
return first_int * second_int
|
|
||||||
|
|
||||||
|
|
||||||
@tool
|
@tool
|
||||||
def redact_email(topic: str) -> str:
|
def redact_email(topic: str) -> str:
|
||||||
"""Use this tool to draft the content of an email based on a topic."""
|
"""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
|
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
|
@tool
|
||||||
def send_message(message: str):
|
def send_message(message: str):
|
||||||
"""Use this function when you need to communicate with Cristian."""
|
"""Use this function when you need to communicate with Cristian."""
|
||||||
@@ -293,6 +58,7 @@ def send_message(message: str):
|
|||||||
|
|
||||||
# Escapar caracteres especiales en Markdown
|
# Escapar caracteres especiales en Markdown
|
||||||
from telebot.util import escape_markdown
|
from telebot.util import escape_markdown
|
||||||
|
|
||||||
safe_message = escape_markdown(message)
|
safe_message = escape_markdown(message)
|
||||||
|
|
||||||
# Enviar mensaje usando MarkdownV2
|
# Enviar mensaje usando MarkdownV2
|
||||||
@@ -306,31 +72,27 @@ def get_company_info(prompt: str) -> str:
|
|||||||
Use this function when you need more information
|
Use this function when you need more information
|
||||||
about the services offered by OneCluster.
|
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)
|
try:
|
||||||
embeddings_model = load_embeddins()
|
docs_split: list = load_split_docs(file_path)
|
||||||
llm = load_llm_openai()
|
embeddings_model = load_embeddins()
|
||||||
create_verctorstore(
|
llm = load_llm_openai()
|
||||||
docs_split,
|
|
||||||
embeddings_model,
|
|
||||||
file_path
|
|
||||||
)
|
|
||||||
retriever = create_retriever(
|
|
||||||
embeddings_model,
|
|
||||||
persist_directory="embeddings/onecluster_info"
|
|
||||||
)
|
|
||||||
qa = create_rag_chain(
|
|
||||||
llm, retriever)
|
|
||||||
|
|
||||||
# prompt: str = "Escribe un parrarfo describiendo cuantos son y
|
# Usar el nombre corregido de la función
|
||||||
# cuales son los servicios que ofrece OneCluster
|
create_vectorstore(docs_split, embeddings_model, file_path)
|
||||||
# y brinda detalles sobre cada uno."
|
|
||||||
response = qa.invoke(
|
|
||||||
{"input": prompt, "chat_history": []}
|
|
||||||
)
|
|
||||||
|
|
||||||
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
|
@tool
|
||||||
@@ -341,6 +103,6 @@ def get_current_date_and_time():
|
|||||||
Returns:
|
Returns:
|
||||||
str: Current date and time in Bogotá, Colombia.
|
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)
|
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
|
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()
|
db_name: str = file_name.replace(".pdf", "").replace(" ", "_").lower()
|
||||||
|
|
||||||
persist_directory: str = f"embeddings/{db_name}"
|
persist_directory: str = f"embeddings/{db_name}"
|
||||||
|
|
||||||
if not os.path.exists(persist_directory):
|
# Crear el directorio si no existe
|
||||||
vectordb = Chroma.from_documents(
|
os.makedirs(persist_directory, exist_ok=True)
|
||||||
persist_directory=persist_directory,
|
|
||||||
documents=docs_split,
|
|
||||||
embedding=embeddings,
|
|
||||||
)
|
|
||||||
|
|
||||||
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_core.prompts import ChatPromptTemplate
|
||||||
|
|
||||||
from langchain_community.tools.tavily_search import TavilySearchResults
|
from langchain_community.tools.tavily_search import TavilySearchResults
|
||||||
from langchain_community.tools.gmail.utils import (
|
from langchain_community.tools.gmail.utils import build_resource_service
|
||||||
build_resource_service,
|
|
||||||
get_gmail_credentials)
|
|
||||||
from langchain_community.agent_toolkits import GmailToolkit
|
from langchain_community.agent_toolkits import GmailToolkit
|
||||||
|
|
||||||
from app.langchain_tools.agent_tools import (
|
from app.langchain_tools.agent_tools import (
|
||||||
redact_email,
|
redact_email,
|
||||||
list_calendar_events,
|
|
||||||
create_calendar_event,
|
|
||||||
get_company_info,
|
get_company_info,
|
||||||
get_current_date_and_time
|
get_current_date_and_time,
|
||||||
)
|
)
|
||||||
|
|
||||||
from langgraph.graph.message import add_messages
|
from langgraph.graph.message import add_messages
|
||||||
@@ -26,33 +22,24 @@ from langgraph.checkpoint.memory import MemorySaver
|
|||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
from typing_extensions import TypedDict
|
from typing_extensions import TypedDict
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
import os
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
llm = ChatOpenAI(
|
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.9)
|
||||||
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
|
# # Crear herramientas
|
||||||
tools = toolkit.get_tools()
|
tools = []
|
||||||
search = TavilySearchResults(max_results=2)
|
search = TavilySearchResults(max_results=2)
|
||||||
tools.extend([
|
tools.extend(
|
||||||
search, redact_email, list_calendar_events,
|
[
|
||||||
create_calendar_event, get_company_info,
|
search,
|
||||||
get_current_date_and_time])
|
get_company_info,
|
||||||
|
get_current_date_and_time,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
# # Definir el sistema prompt
|
# # Definir el sistema prompt
|
||||||
system_prompt = ChatPromptTemplate.from_messages(
|
system_prompt = ChatPromptTemplate.from_messages(
|
||||||
@@ -61,42 +48,49 @@ system_prompt = ChatPromptTemplate.from_messages(
|
|||||||
"system",
|
"system",
|
||||||
"Eres Mariana, el asistente virtual de OneCluster, una empresa de "
|
"Eres Mariana, el asistente virtual de OneCluster, una empresa de "
|
||||||
"software que ofrece soluciones personalizadas. Asume el tono 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",
|
"system",
|
||||||
"Evita mencionar o hacer alusión a las herramientas que utilizas "
|
"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}"),
|
("placeholder", "{messages}"),
|
||||||
]
|
]
|
||||||
@@ -115,7 +109,7 @@ graph = create_react_agent(
|
|||||||
tools=tools,
|
tools=tools,
|
||||||
state_schema=State,
|
state_schema=State,
|
||||||
state_modifier=system_prompt,
|
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
|
# # Edit this to add the chain you want to add
|
||||||
add_routes(
|
add_routes(app, llm, path="/openai")
|
||||||
app,
|
|
||||||
llm,
|
|
||||||
path="/openai"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/process_text")
|
@app.post("/process_text")
|
||||||
@@ -140,9 +130,8 @@ async def process_text(request: Request):
|
|||||||
# Procesar el texto con LangChain
|
# Procesar el texto con LangChain
|
||||||
events = graph.stream(
|
events = graph.stream(
|
||||||
{"messages": [("user", user_input)], "is_last_step": False},
|
{"messages": [("user", user_input)], "is_last_step": False},
|
||||||
config={"configurable": {
|
config={"configurable": {"thread_id": "thread-1", "recursion_limit": 50}},
|
||||||
"thread_id": "thread-1", "recursion_limit": 50}},
|
stream_mode="updates",
|
||||||
stream_mode="updates"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Preparar la respuesta
|
# Preparar la respuesta
|
||||||
@@ -151,24 +140,33 @@ async def process_text(request: Request):
|
|||||||
if "agent" in event:
|
if "agent" in event:
|
||||||
response.append(event["agent"]["messages"][-1].content)
|
response.append(event["agent"]["messages"][-1].content)
|
||||||
|
|
||||||
return JSONResponse(content={'response': response})
|
return JSONResponse(content={"response": response})
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
config = {"configurable": {"thread_id": "thread-1", "recursion_limit": 50}}
|
config = {"configurable": {"thread_id": "thread-1", "recursion_limit": 50}}
|
||||||
|
|
||||||
while True:
|
# Modo interactivo por defecto
|
||||||
user_input = input("User: ")
|
import sys
|
||||||
if user_input.lower() in ["quit", "exit", "q"]:
|
|
||||||
print("Goodbye!")
|
|
||||||
break
|
|
||||||
|
|
||||||
events = graph.stream({
|
if "--server" not in sys.argv:
|
||||||
"messages": [("user", user_input)],
|
while True:
|
||||||
"is_last_step": False},
|
user_input = input("User: ")
|
||||||
config, stream_mode="updates")
|
if user_input.lower() in ["quit", "exit", "q"]:
|
||||||
|
print("Goodbye!")
|
||||||
|
break
|
||||||
|
|
||||||
for event in events:
|
events = graph.stream(
|
||||||
if "agent" in event:
|
{"messages": [("user", user_input)], "is_last_step": False},
|
||||||
print(
|
config,
|
||||||
f"\nAsistente: {event['agent']['messages'][-1].content}\n")
|
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"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- .:/code
|
- .:/code
|
||||||
|
- ./google_credentials.json:/code/google_credentials.json
|
||||||
|
- ./tokens:/code/tokens
|
||||||
environment:
|
environment:
|
||||||
- PYTHONUNBUFFERED=1
|
- PYTHONUNBUFFERED=1
|
||||||
|
- GOOGLE_APPLICATION_CREDENTIALS=/code/google_credentials.json
|
||||||
command: >
|
command: >
|
||||||
uvicorn app.server:app --host 0.0.0.0 --port 8080
|
uvicorn app.server:app --host 0.0.0.0 --port 8080
|
||||||
env_file:
|
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]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.11"
|
python = "^3.9"
|
||||||
uvicorn = "^0.23.2"
|
uvicorn = "^0.23.2"
|
||||||
langserve = {extras = ["server"], version = ">=0.0.30"}
|
langserve = {extras = ["server"], version = ">=0.0.30"}
|
||||||
pydantic = "<3"
|
pydantic = "<3"
|
||||||
langgraph = "^0.2.28"
|
langgraph = "^0.2.28"
|
||||||
langchain-community = "^0.3.1"
|
langchain = "^0.3.8"
|
||||||
|
langchain-community = "^0.3.8"
|
||||||
langchain-openai = "^0.2.5"
|
langchain-openai = "^0.2.5"
|
||||||
langchain-chroma = "^0.1.4"
|
langchain-chroma = "^0.1.4"
|
||||||
google = "^3.0.0"
|
google = "^3.0.0"
|
||||||
google-auth = "^2.35.0"
|
google-auth = "^2.35.0"
|
||||||
google-auth-oauthlib = "^1.2.0"
|
google-auth-oauthlib = "^1.1.0"
|
||||||
google-api-python-client = "^2.131.0"
|
google-auth-httplib2 = "^0.1.0"
|
||||||
|
google-api-python-client = "^2.108.0"
|
||||||
flake8 = "^7.1.1"
|
flake8 = "^7.1.1"
|
||||||
httpx = "^0.27.2"
|
httpx = "^0.27.2"
|
||||||
pytest = "^8.3.3"
|
pytest = "^8.3.3"
|
||||||
@@ -31,8 +33,6 @@ pytz = "^2024.2"
|
|||||||
telebot = "^0.0.5"
|
telebot = "^0.0.5"
|
||||||
pypdf = "^5.1.0"
|
pypdf = "^5.1.0"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
langchain-cli = ">=0.0.15"
|
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