Procesamiento de PDFs y creación de resúmenes con LangChain
Resumen
¿Cómo trabajar con cadenas en procesamiento de lenguaje?
Las cadenas son fundamentales en LangChain, ya que permiten crear flujos de trabajo donde cada paso es un proceso diferente. Se ingresa un texto al inicio de la cadena y se transforma a través de diversos eslabones hasta obtener una respuesta utilizando un modelo de lenguaje. En esta guía, nos enfocaremos en las cadenas fundacionales y de utilidad, y en cómo cargarlas y procesarlas con ayuda de herramientas esenciales.
¿Cómo se carga un PDF para procesar con LangChain?
Para manejar documentos no estructurados como PDFs, debes instalar librerías especializadas:
OnStructure: Permite a LangChain trabajar con diversos tipos de documentos no estructurados.
PyPDF: Utilizada por LangChain para cargar y adecuar PDFs.
ChromaDB: Una base de datos vectorial eficiente para gestionar embeddings.
Después de instalar estas herramientas, utiliza la librería requests para descargar un PDF desde una URL específica. Al abrirlo, guárdalo localmente para su posterior tratamiento.
import requests
# Obtención del PDF desde la URLurl ="URL_DEL_PDF"r = requests.get(url)withopen("publickeycryptography.pdf","wb")as f: f.write(r.content)
¿Cómo se procesa un PDF con PyPDFLoader en LangChain?
Para utilizar LangChain, necesitas su módulo DocumentLoaders y específicamente PyPDFLoader:
from langchain.document_loaders import PyPDFLoader
# Carga del PDF en el formato adecuadoloader = PyPDFLoader("publickeycryptography.pdf")data = loader.load()
¿Cómo se integran los Embeddings con OpenAI y ChromaDB?
Una vez procesado el PDF, OpenAI embeddings deben importarse para convertir los datos al formato numérico requerido:
from langchain.embeddings import OpenAIEmbeddings
# Conversión del PDF en un formato embebidoembeddings = OpenAIEmbeddings()embeddings_data = embeddings.embed_documents(data)
Finalmente, almacena estos embeddings en ChromaDB para utilizarlos con las cadenas de utilidad:
from langchain.vectorstores import Chroma
# Almacenamiento de embeddings en ChromaDBvector_store = Chroma.from_embeddings(embeddings_data)
¿Cómo resumir un texto extenso con LoadSummarizeChain?
LangChain permite resumir documentos largos con herramientas adecuadas, como LoadSummarizeChain. Esta cadena puede manejar documentos extensos dividiéndolos en partes manejables y resumiéndolos individualmente, combinando los resúmenes individuales en uno final usando un enfoque MapReduce:
from langchain.chains import load_summarize_chain
# Configuración y ejecución de la cadena que resumesummary_chain = load_summarize_chain( model=LLM_DaVinci, chain_type="MapReduce")summary = summary_chain.run(data)
¿Qué beneficios ofrece el uso de prompts?
El uso de prompts personalizados permite mejores resultados en los resúmenes generados. Puedes definir un prompt estilo mexicano, por ejemplo:
from langchain.prompts import PromptTemplate
template_text ="Escribe un resumen bien chido del siguiente rollo: {text}. Resumen corto con slang mexicano."prompt_template = PromptTemplate(template=template_text, input_variables=["text"])
Con el chain tipo Stuff, utilizas este prompt para generar resúmenes más adaptados culturalmente:
informal_chain = load_summarize_chain( model=LLM_DaVinci, chain_type="Stuff", prompt_template=prompt_template, verbose=True)# Ejecución de la cadena con un extracto del PDFresumen_mx = informal_chain.run(data[:2])
En esencia, el tipo Stuff limita el contexto al tamaño del prompt, lo que significa que grandes documentos deben ser acortados antes de ingresar al modelo. Sin embargo, permite la creación de recomendaciones culturalmente apropiadas y específicas.
En resumen, LangChain abre la puerta a una eficiente navegación y procesamiento de grandes cantidades de texto con un grado de personalización notorio, permitiendo a los usuarios crear flujos de trabajo precisos y culturalmente sensibles.
Buenas, no me parece tan grave que el codigo no este actualizado, en la vida profesional nos toca leer documentacion, es muy sencillo entrar a la documentacion y readaptar el codigo, no hay que ser genio para ello.
Animos!
El código usado en este video ya está obsoleto (21-2-24).
Por ejemplo el método run ya no se aplica.
Hay prevista alguna actualización de los videos?
Lo digo porque ahora mismo ya no sirve.
Gracias.
Así es, yo paré el curso acá porque es inutil seguirlo, ya no da ningún código, y como simplemente se habla mientras se corre código sin explicar con gráficos o algo más visual, sale más eficiente simplemente leer la documentación y ya.
Yo creo que vale la pena hacer el curso completo, aunque no todo el código esté actualizado. Para mí, lo importante es entender la idea general: cómo funciona LangChain y qué cosas se pueden construir con esta herramienta. Con ese panorama más claro, después podés buscar cómo implementarlo por tu cuenta con versiones más actuales.
Eso sí, estoy de acuerdo en que la falta de actualización es un problema y puede dificultar el aprendizaje.
#%%from langchain.chains.summarize.chainimportload_summarize_chainfrom langchain.promptsimportChatPromptTemplatefrom langchain.chains.llmimportLLMChainfrom langchain.chains.combine_documents.stuffimportStuffDocumentsChain#%%prompt_template =ChatPromptTemplate([("system","Eres un sistema de resumen didactico, dando como resultados resumenes con un lenguaje mas amigable para el usuario"),("user","Resume este documento {doc}")], input_variables=['doc'])#%%# DefineLLM chain
llm_chain =LLMChain(llm=llm_gpt4_1, prompt=prompt_template)#%%stuff_chain =StuffDocumentsChain(llm_chain=llm_chain, document_variable_name="doc")#%%stuff_chain.run(document[:2])```Este es el código que use con la nueva versión de langchain.Comparto la documentación que usé
Gracias
Algo que me ha servido mucho para entender mejor este tema (por que igual es complejo), es separar los procesos por pasos:
1. pasar el pdf a Document de Langchain
2. hacer un resumen previo para cada pagina
3. hacer el prompt-template
4. hacer resumen en español mexicano.
Creo que puede ser útil.
Lanchain Introdujo una nueva forma en que se declaran y usan las chain, ahora usa LCEL (Langchaing Expression Language). EL cual es una sintaxis declarativa para componer chains usando el "Pipe operator ( | )".
Summaryze as "stuff chain type" Code Example:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
# Allows wraps a regular python function to make it compatible with LCEL chains.from langchain_core.runnables import RunnableLambda
# Converts the LLM output into a plain stringfrom langchain_core.output_parsers import StrOutputParser
defformat_docs(docs):""" Combine document pages content into a single string to be used as context in the prompt"""return"\n\n".join([doc.page_content for doc in docs[:2]])# Define the prompt that generates summarysummarize_prompt = ChatPromptTemplate.from_template("""Please provide a comprehensive summary of the following document:
{context}
Summary:""")# Initialize openAI LLMllm = ChatOpenAI(model="gpt-4o-mini", temperature=0)# create the LCEL chain defining steps separed by the pipe operator ( | ) summarize_docs_chain =({"context": RunnableLambda(format_docs)}| summarize_prompt
| llm
| StrOutputParser())# Gets the summary executing the LCEL chain.summary = summarize_docs_chain.invoke(data)
Para los que quieren probar todo lo de la clase con PDFs distintos, pueden usar el siguiente sitio para que carguen los PDF de manera temporal y solo cambien la url
El vectorstore que se crea en esta clase no se uso para ninguno de los ejemplos...
La verdad muy mal que tengan código que NO es funcional, uno pierde más tiempo tratanto de arreglar cosas que realmente aprendiendo.
Les recomiendo pagar la suscripción a Medium, que estar perdiendo el tiempo aquí.
Super interesante el curso!
Me queda la duda porque usas Davinci para resumir y no gtp-3.5. Funciona mejor para esta tarea?
Aqune algo complejo, veo mucho potencial en lo que podemos lograr con LangChain 🦜⛓
no es tan complejo esa es la idea de langchain , langchain nos permite no centrarnos tanto en la parte conceptual si no en lo aplicativo
primero Se descarga un archivo PDF y se procesa.
Este archivo se convierte en "embeddings", que se guardan en una base de datos especializada. Aunque la ciencia detrás de los embeddings es compleja, en la práctica solo necesitamos saber que se utilizan para que los modelos de lenguaje (LLM) comprendan y procesen texto.
Utilizando la función "load_summarize_chain", se establece el tipo de LLM y cadena, y se utiliza la base de datos de embeddings como parámetro y listo casi como magia nos da el resumen
incluso podemos darle instrucciones al llm para que actue de cierta forma acosta de perder la cantidad de informacion que puede proecesar
⛓️ Cadenas (Chains)
Utilizar un LLM de forma aislada está bien para aplicaciones sencillas, pero las aplicaciones más complejas requieren encadenar LLM, ya sea entre sí o con otros componentes.
.
LangChain proporciona la interfaz Chain para generar aplicaciones más específicas. Ya que la idea de componer componentes en cadena, simplifica drásticamente su especificación, haciendo más modular la implementación de aplicaciones complejas, lo que a su vez facilita mucho la depuración, el mantenimiento y la mejora de nuestras aplicaciones.
.
📝 Resumen (Summarization)
Se puede utilizar una cadena de resumen para resumir (summarize) múltiples documentos. Una forma es introducir múltiples documentos más pequeños, después de haberlos dividido en trozos, y operar sobre ellos con una MapReduceDocumentsChain. También puede elegir que la cadena que realiza el resumen sea una cadena StuffDocumentsChain o una cadena RefineDocumentsChain.
.
Supongamos una conversación en formato .txt:
Elena: Perfect, Carlos, Ana, Juan, thank you for your feedback. Regarding priorities, we continue to focus on completing the search functionality as it is essential for the launch. Carlos, can you talk to Ana later to review the design changes?
Carlos: Of course, Elena, I will be happy to do that.
Ana: Carlos, I will send you a meeting request for that.
Juan: Regarding the implementation of the search function, I have some doubts about the integration with the third-party API we discussed yesterday. Could we go over that before we start?
Elena: Certainly, Juan. What time would be convenient for you?
Juan: Could it be at 10:30? I would have time to review the documentation before the meeting.
Elena: Sure, lets schedule the meeting for 10:30 then. Also, remember that today at 3 PM, we will have our weekly project update meeting, so lets make sure we are prepared to update the whole team.
Ana: Understood, I will be ready for that meeting.
Carlos: Same here, I will be ready to provide a solid update.
Juan: I will be ready too and hope to have some answers about the integration by then.
Elena: Perfect, that sounds great. In summary, today we will focus on the search functionality, review the design changes, and clarify any doubts about the integration with the third-party API. Lets work with energy and efficiency, team!
{
text: "Elena, Carlos, Ana, and Juan discussed their ongoing project, focusing on the completion of the search functionality. Carlos agreed to review design changes with Ana, while Juan expressed concerns about integrating a third-party API. A meeting was scheduled for 10:30 to discuss this. Elena reminded the team about a project update meeting at 3 PM, and everyone confirmed their readiness to provide updates. The team agreed to focus on the search functionality, design changes, and API integration issues.",
__run: undefined
}
Like ❤️ si lo leíste como chilango la cadena_que_resume_con_salng_mx XD
Qué fastidio usar notebooks para esto, de verdad. Me parece súper incómodo; era mejor armar un proyecto local como cualquier otro. LangChain se aprovecha mucho mejor en local, ya que Colab maneja sus propios entornos de manera aislada. No le veo sentido a usar Jupyter para esto, menos aún cuando estamos trabajando con llamadas a APIs. Distinto sería si estuviéramos corriendo un modelo pequeño de forma local como prueba. Pero Platzi se empeña en usar OpenAI bueno para ¿qué usar llamadass API? Primera vez que me quejo de un curso en platzi. No estoy conforme no.
La parte de with open('public_key_cryptography.pdf', 'wb') as f: f.write(response.content) se utiliza para guardar el contenido de la respuesta en un archivo llamado 'public_key_cryptography.pdf'.
Al final para que se usa estas líneas de código en el contexto de esta clase? porque yo veo que se usa es la variable "data"