Caricatore JSON

  • JSON (JavaScript Object Notation) è un formato di file standard aperto e un formato di scambio dati che utilizza testo leggibile per memorizzare e trasmettere oggetti di dati composti da coppie attributo-valore e array (o altri valori serializzabili).

JSON Lines è un formato di file in cui ciascuna riga è un valore JSON valido.

JSONLoader analizza i file JSON utilizzando un modello jq specificato e utilizza il pacchetto jq Python. Per una documentazione dettagliata sulla sintassi jq, consultare la documentazione Python rilevante.

from langchain_community.document_loaders import JSONLoader
import json
from pathlib import Path
from pprint import pprint

file_path = './esempio_dati/chat_facebook.json'
data = json.loads(Path(file_path).read_text())
pprint(data)
{'image': {'creation_timestamp': 1675549016, 'uri': 'immagine_del_chat.jpg'},
 'is_still_participant': True,
 'joinable_mode': {'link': '', 'mode': 1},
 'magic_words': [],
 'messages': [{'content': 'Ciao!',
               'sender_name': 'Utente 2',
               'timestamp_ms': 1675597571851},
              {'content': 'Non ti preoccupare! Ciao',
               'sender_name': 'Utente 1',
               'timestamp_ms': 1675597435669},
              {'content': 'No, mi dispiace, è stato un mio errore, quello blu '
                          'non è in vendita',
               'sender_name': 'Utente 2',
               'timestamp_ms': 1675596277579},
              {'content': 'Pensavo che stessi vendendo quello blu!',
               'sender_name': 'Utente 1',
               'timestamp_ms': 1675595140251},
              {'content': 'Non sono interessato a questa borsa. Sono interessato '
                          'a quella blu!',
               'sender_name': 'Utente 1',
               'timestamp_ms': 1675595109305},
              {'content': 'Ecco $129',
               'sender_name': 'Utente 2',
               'timestamp_ms': 1675595068468},
              {'photos': [{'creation_timestamp': 1675595059,
                           'uri': 'url_di_una_foto.jpg'}],
               'sender_name': 'Utente 2',
               'timestamp_ms': 1675595060730},
              {'content': 'Online costa almeno $100',
               'sender_name': 'Utente 2',
               'timestamp_ms': 1675595045152},
              {'content': 'Quanto vuoi?',
               'sender_name': 'Utente 1',
               'timestamp_ms': 1675594799696},
              {'content': 'Buongiorno! $50 è troppo poco.',
               'sender_name': 'Utente 2',
               'timestamp_ms': 1675577876645},
              {'content': 'Ciao! Sono interessato alla tua borsa. Offro $50. '
                          'Fammi sapere se sei interessato. Grazie!',
               'sender_name': 'Utente 1',
               'timestamp_ms': 1675549022673}],
 'participants': [{'name': 'Utente 1'}, {'name': 'Utente 2'}],
 'thread_path': 'inbox/Chat tra Utente 1 e Utente 2',
 'title': 'Chat tra Utente 1 e Utente 2'}

Usando JSONLoader

Supponiamo che vogliamo estrarre i valori dal campo content sotto la chiave messages nei dati JSON. Utilizzando JSONLoader possiamo facilmente completare questo compito.

loader = JSONLoader(
    file_path='./example_data/facebook_chat.json',
    jq_schema='.messages[].content')

data = loader.load()
pprint(data)
[Document(page_content='Ciao!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 1}),
     Document(page_content='Oh tranquillo! Ciao', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 2}),
     Document(page_content='No, mi dispiace, è stato un mio errore, il blu non è in vendita', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 3}),
     Document(page_content='Pensavo stessi vendendo quello blu!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 4}),
     Document(page_content='Non sono interessato a questa borsa. Sono interessato a quella blu!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 5}),
     Document(page_content='Ecco $129', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 6}),
     Document(page_content='', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 7}),
     Document(page_content='Online è almeno $100', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 8}),
     Document(page_content='Quanto ne vuoi?', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 9}),
     Document(page_content='Buongiorno! $50 è troppo poco.', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 10}),
     Document(page_content='Ciao! Sono interessato alla tua borsa. Offro $50. Fammi sapere se sei interessato. Grazie!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 11})]

File JSON Lines

Se vuoi caricare documenti da un file JSON Lines, devi passare json_lines=True e specificare lo jq_schema per estrarre page_content da un singolo oggetto JSON.

file_path = './example_data/facebook_chat_messages.jsonl'
pprint(Path(file_path).read_text())
('{"sender_name": "Utente 2", "timestamp_ms": 1675597571851, "content": "Arrivederci!"}\n'
     '{"sender_name": "Utente 1", "timestamp_ms": 1675597435669, "content": "Oh non ti preoccupare! Arrivederci"}\n'
     '{"sender_name": "Utente 2", "timestamp_ms": 1675596277579, "content": "No scusa è stato un mio errore, il blu non è in vendita"}\n')
loader = JSONLoader(
    file_path='./example_data/facebook_chat_messages.jsonl',
    jq_schema='.content',
    json_lines=True)

data = loader.load()
pprint(data)
[Document(page_content='Arrivederci!', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat_messages.jsonl', 'seq_num': 1}),
     Document(page_content='Oh non ti preoccupare! Arrivederci', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat_messages.jsonl', 'seq_num': 2}),
     Document(page_content='No scusa è stato un mio errore, il blu non è in vendita', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat_messages.jsonl', 'seq_num': 3})]

Un'altra opzione è impostare jq_schema='.' e fornire content_key:

loader = JSONLoader(
    file_path='./example_data/facebook_chat_messages.jsonl',
    jq_schema='.',
    content_key='sender_name',
    json_lines=True)

data = loader.load()
pprint(data)
[Document(page_content='Utente 2', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat_messages.jsonl', 'seq_num': 1}),
     Document(page_content='Utente 1', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat_messages.jsonl', 'seq_num': 2}),
     Document(page_content='Utente 2', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat_messages.jsonl', 'seq_num': 3})]

Estrazione dei metadati

Di solito, vogliamo includere i metadati da un file JSON nel documento che creiamo dal contenuto.

Di seguito viene mostrato come utilizzare JSONLoader per estrarre i metadati.

Nell'esempio precedente, non abbiamo raccolto i metadati, ma siamo riusciti a specificare nello schema la posizione da cui il valore page_content può essere estratto direttamente.

.messages[].content

Nell'esempio attuale, dobbiamo dire al caricatore di iterare sui record nel campo messages. Quindi, lo schema jq_schema deve essere:

.messages[]

Questo ci consente di passare i record (dizionari) alla "metadata_func" che deve essere implementata. La "metadata_func" è responsabile per identificare quali informazioni del record devono essere incluse nei metadati da memorizzare nell'oggetto "Document" finale.

Inoltre, ora dobbiamo specificare esplicitamente il parametro content_key nel caricatore per estrarre il valore "page_content" da quale chiave nel record.

def metadata_func(record: dict, metadata: dict) -> dict:

    metadata["sender_name"] = record.get("sender_name")
    metadata["timestamp_ms"] = record.get("timestamp_ms")

    return metadata

loader = JSONLoader(
    file_path='./example_data/facebook_chat.json',
    jq_schema='.messages[]',
    content_key="content",
    metadata_func=metadata_func
)

data = loader.load()
pprint(data)
[Document(page_content='Ciao!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 1, 'sender_name': 'Utente 2', 'timestamp_ms': 1675597571851}),
     Document(page_content='Oh, nessun problema! Ciao', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 2, 'sender_name': 'Utente 1', 'timestamp_ms': 1675597435669}),
     Document(page_content='No, mi dispiace, è stato un mio errore. Quello blu non è in vendita', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 3, 'sender_name': 'Utente 2', 'timestamp_ms': 1675596277579}),
     Document(page_content='Pensavo stessi vendendo quello blu!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 4, 'sender_name': 'Utente 1', 'timestamp_ms': 1675595140251}),
     Document(page_content='Non sono interessato a questa borsa. Mi interessa quella blu!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 5, 'sender_name': 'Utente 1', 'timestamp_ms': 1675595109305}),
     Document(page_content='Ecco $129', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 6, 'sender_name': 'Utente 2', 'timestamp_ms': 1675595068468}),
     Document(page_content='', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 7, 'sender_name': 'Utente 2', 'timestamp_ms': 1675595060730}),
     Document(page_content='Online costa almeno $100', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 8, 'sender_name': 'Utente 2', 'timestamp_ms': 1675595045152}),
     Document(page_content='Quanto ne vuoi?', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 9, 'sender_name': 'Utente 1', 'timestamp_ms': 1675594799696}),
     Document(page_content='Buongiorno! $50 è troppo poco.', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 10, 'sender_name': 'Utente 2', 'timestamp_ms': 1675577876645}),
     Document(page_content='Ciao! Sono interessato alla tua borsa. Offro $50. Fammi sapere se sei interessato. Grazie!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 11, 'sender_name': 'Utente 1', 'timestamp_ms': 1675549022673})]

Qui possiamo vedere che questi file contengono già metadati correlati al contenuto che abbiamo estratto.

Funzione metadata_func

Come mostrato sopra, metadata_func riceve i metadati predefiniti generati da JSONLoader. Questo consente agli utenti di avere pieno controllo sul formato dei metadati.

Ad esempio, i metadati predefiniti contengono le chiavi source e seq_num. Tuttavia, i dati JSON potrebbero già contenere queste chiavi. Gli utenti possono utilizzare metadata_func per rinominare le chiavi predefinite e utilizzare le chiavi presenti nei dati JSON.

L'esempio seguente dimostra come modificare il source per includere solo le informazioni sulla fonte del file relative alla directory langchain.

def metadata_func(record: dict, metadata: dict) -> dict:

    metadata["sender_name"] = record.get("sender_name")
    metadata["timestamp_ms"] = record.get("timestamp_ms")

    if "source" in metadata:
        source = metadata["source"].split("/")
        source = source[source.index("langchain"):]
        metadata["source"] = "/".join(source)

    return metadata

loader = JSONLoader(
    file_path='./example_data/facebook_chat.json',
    jq_schema='.messages[]',
    content_key="content",
    metadata_func=metadata_func
)

data = loader.load()
pprint(data)
[Documento(contenuto_pagina='Ciao!', metadati={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 1, 'sender_name': 'Utente 2', 'timestamp_ms': 1675597571851}),
     Documento(contenuto_pagina='Oh nessun problema! Ciao', metadati={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 2, 'sender_name': 'Utente 1', 'timestamp_ms': 1675597435669}),
     ...
     ...
     ... (restante contenuto invariato per brevità) ...
     ...
     ...
]

Strutture JSON comuni per l'utilizzo dei modelli jq

L'elenco seguente fornisce possibili jq_schema che gli utenti possono utilizzare come riferimento per estrarre contenuti dai dati JSON in base alla struttura.

JSON        -> [{"text": ...}, {"text": ...}, {"text": ...}]
jq_schema   -> ".[].text"

JSON        -> {"key": [{"text": ...}, {"text": ...}, {"text": ...}]}
jq_schema   -> ".key[].text"

JSON        -> ["...", "...", "..."]
jq_schema   -> ".[]"