Los objetos Document son abstracciones clave dentro de LlamaIndex.
Un Document es un contenedor genérico para cualquier fuente de datos, por ejemplo, un PDF, el output de una API o datos recuperados de una base de datos. Se pueden construir manualmente, o crearse automáticamente via data loaders, también conocidos como Data Connectors (LlamaHub).
Por defecto, un Document almacena texto junto a otros atributos, por ejemplo:
metadata– un diccionario con pares clave-valor que se pueden agregar al texto.relationships– un diccionario que contiene las relaciones con otros Document.
Se pueden añadir otras como keywords, summary o questions, todo dependerá del caso de uso que quieras implementar.
En la documentación oficial de LlamaIndex te encontrarás con una nota que dice: we have beta support for allowing Documents to store images, and are actively working on improving its multimodal capabilities.
Por otro lado, un Node representa un «chunk» de un Document, es decir un fragmento del objeto Document, o dicho de otra manera, un Document esta formado por 1 o varios Nodes. Ese fragmento puede ser de texto, una imágen u otra cosa. Al igual que los Document, los Nodes contienen metadatos e información de las relaciones con los otros nodos. Por defecto, cada Node derivado de Document herederá los mismos metadatos de ese Document, por ejemplo, un file_name se propagará a cada Node.
¿Cómo se define un objeto Document en LlamaIndex?
Cómo mencionábamos arriba, los objetos Document se pueden crear automáticamente vía Data Loaders, o construídos manualmente. Por defecto, todos los Data Connectors (incluídos los que puedes encontrar vía LlamaHub) devuelven un objeto Document a través de la función load_data.
from llama_index.core import SimpleDirectoryReader
documents = SimpleDirectoryReader("./data").load_data()
¿Qué es SimpleDirectoryReader?
SimpleDirectoryReader es el conector de datos más utilizado y que Simplemente tienes que pasar un directorio de entrada o una lista de archivos. La clase automáticamente seleccionará el mejor lector de archivos según las extensiones de archivo. Puedes verlo en profundidad aquí.
En este caso, como data voy a utilizar un archivo PDF llamado TSLA-Q1-2024-Update.pdf que he descargado de aquí, pero tu puedes utilizar la fuente de datos que quieras, siempre y cuando tenga una de estas extensiones (.hwp, .pdf, .docx, .pptx, .ppt, .pptm, .jpg, .png, .jpeg, .mp3, .mp4, .csv, .epub, .md, .mbox, .ipynb)
Si imprimimos documentos por pantalla, vermos una lista con diferentes objetos Document, cada uno con un identificador único. Aunque hayas utilizado otra fuente de información, verás algo similar a:
[Document(id_=’b7497362-1117-4f98-b483-08148f09cd5f’, embedding=None, metadata={‘page_label’: ‘1’, ‘file_name’: ‘TSLA-Q1-2024-Update.pdf’, ‘file_path’: ‘c:\\Users\\Usuario\\Downloads\\medium\\data\\TSLA-Q1-2024-Update.pdf’, ‘file_type’: ‘application/pdf’, ‘file_size’: 7458951, ‘creation_date’: ‘2024-06-03’, ‘last_modified_date’: ‘2024-06-03’}, excluded_embed_metadata_keys=[‘file_name’, ‘file_type’, ‘file_size’, ‘creation_date’, ‘last_modified_date’, ‘last_accessed_date’], excluded_llm_metadata_keys=[‘file_name’, ‘file_type’, ‘file_size’, ‘creation_date’, ‘last_modified_date’, ‘last_accessed_date’], relationships={}, text=’Q1 2024 Update\n1′, start_char_idx=None, end_char_idx=None, text_template='{metadata_str}\n\n{content}’, metadata_template='{key}: {value}’, metadata_seperator=’\n’)
Si lo formateamos un poco:
import json
# Importamos la clase Document de LlamaIndex
from llama_index.core import Document
document = Document(id_='b7497362-1117-4f98-b483-08148f09cd5f', embedding=None, metadata={'page_label': '1', 'file_name': 'TSLA-Q1-2024-Update.pdf', 'file_path': 'c:\\Users\\Usuario\\Downloads\\medium\\data\\TSLA-Q1-2024-Update.pdf', 'file_type': 'application/pdf', 'file_size': 7458951, 'creation_date': '2024-06-03', 'last_modified_date': '2024-06-03'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={}, text='Q1 2024 Update\n1', start_char_idx=None, end_char_idx=None, text_template='{metadata_str}\n\n{content}', metadata_template='{key}: {value}', metadata_seperator='\n')
json_document = json.dumps(document.__dict__, indent=4)
print(json_document)
Así se debería ver:
{
"id_": "b7497362-1117-4f98-b483-08148f09cd5f",
"embedding": null,
"metadata": {
"page_label": "1",
"file_name": "TSLA-Q1-2024-Update.pdf",
"file_path": "c:\\Users\\Usuario\\Downloads\\medium\\data\\TSLA-Q1-2024-Update.pdf",
"file_type": "application/pdf",
"file_size": 7458951,
"creation_date": "2024-06-03",
"last_modified_date": "2024-06-03"
},
"excluded_embed_metadata_keys": [
"file_name",
"file_type",
"file_size",
"creation_date",
"last_modified_date",
"last_accessed_date"
],
"excluded_llm_metadata_keys": [
"file_name",
"file_type",
"file_size",
"creation_date",
"last_modified_date",
"last_accessed_date"
],
"relationships": {},
"text": "Q1 2024 Update\n1",
"start_char_idx": null,
"end_char_idx": null,
"text_template": "{metadata_str}\n\n{content}",
"metadata_template": "{key}: {value}",
"metadata_seperator": "\n"
}
A continuación, se explica cada parte de la salida:
"id_": "b7497362-1117-4f98-b483-08148f09cd5f": Este es el identificador único asignado alDocument. Sirve para distinguir esteDocumentde otros en el índice."embedding": null: Este atributo representa el embedding delDocument, que es una representación vectorial del contenido del texto. En este caso, el valor esnull, lo que indica que no se ha generado un embedding para esteDocument."metadata": { ... }: Este objeto contiene metadatos adicionales asociados alDocument. En este caso, incluye información como el número de página ("page_label": "1"), el nombre del archivo ("file_name": "TSLA-Q1-2024-Update.pdf"), la ruta del archivo ("file_path": "c:\\Users\\Usuario\\Downloads\\medium\\data\\TSLA-Q1-2024-Update.pdf"), el tipo de archivo ("file_type": "application/pdf"), el tamaño del archivo en bytes ("file_size": 7458951), la fecha de creación ("creation_date": "2024-06-03") y la fecha de última modificación ("last_modified_date": "2024-06-03")."excluded_embed_metadata_keys": [...]y"excluded_llm_metadata_keys": [...]: Estas listas especifican las claves de metadatos que se excluirán al generar embeddings o al interactuar con el modelo de lenguaje (LLM) respectivamente. En este caso, se excluyen las claves relacionadas con el nombre del archivo, tipo de archivo, tamaño del archivo, fecha de creación, fecha de última modificación y fecha de último acceso."relationships": {}: Este objeto representa las relaciones delDocumentcon otros documentos o nodos en el índice. En este caso, está vacío, lo que indica que no se han definido relaciones para este Document."text": "Q1 2024 Update\n1": Este es el contenido textual delDocument. En este caso, contiene el título «Q1 2024 Update» seguido de un salto de línea y el número «1»."start_char_idx": nully"end_char_idx": null: Estos atributos representan los índices de inicio y fin de los caracteres del contenido textual dentro de un documento más grande. En este caso, ambos valores sonnull, lo que indica que no se han especificado estos índices."text_template": "{metadata_str}\n\n{content}","metadata_template": "{key}: {value}"y"metadata_seperator": "\n": Estos atributos definen las plantillas y el separador utilizados para formatear la representación textual delDocumentcuando se combina con los metadatos.
También puedes decidir construir los Document manualmente.
LlamaIndex expone la estructura del objeto:
from llama_index.core import Document
text_list = ["Este es el texto del primer Document", "Este es el texto del segundo Document"]
documents = [Document(text=t) for t in text_list]
documents
[Document(id_=’8af92c72-e268-4a12-ab61-410989ea9951′, embedding=None, metadata={}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationships={}, text=’Este es el texto del primer Document‘, start_char_idx=None, end_char_idx=None, text_template='{metadata_str}\n\n{content}’, metadata_template='{key}: {value}’, metadata_seperator=’\n’)
Para acelerar el prototipado y el desarrollo, puedes crear un document usando un texto por defecto con este método document = Document.example()
Lee estos artículos relacionados:
SimpleDirectoryReader. ¿Cómo cargar datos de archivos locales con LlamaIndex?
CREDITS: https://docs.llamaindex.ai/en/latest/module_guides/loading/documents_and_nodes/usage_documents/