Files
llmware-ai--llmware/solutions/sources/parse_csv_custom.py
T
wehub-resource-sync 86db9aae8e
Documentation / build (push) Has been cancelled
Documentation / deploy (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:34:55 +08:00

174 lines
7.2 KiB
Python

""" This script illustrates options for parsing csv and tsv files into a Library in LLMWare, including methods for
mapping custom configured csv or tsv file, which is intended for use with 'pseudo-db' CSV files
Option #1 - Standard CSV/TSV Parsing
-- when using a bulk ingest Parsing method, the parser will route csv files to the 'standard'
TextParser - which will look to extract and 'aggregate' the text from the csv as source content, and
add to "text" and/or "table" attributes -> no "structure" information or targeted keys are captured
-- the standard TextParser() is designed for ad hoc extraction of text content
-- if file is csv, then by default delimiter assumed to be ',' (which can be adjusted)
-- if file is tsv, then by default delimited assumed to be '\t' (which can be adjusted)
-- this is illustrated in example 1 and example 2 below.
Option #2 - Custom Configured CSV/TSV Parsing
-- if the CSV file is a pseudo-db with structured attributes, then it can be configured using a special
parsing method, as outlined below in examples 3 and 4.
-- the benefit of this custom mapping is that key column attributes will be saved as "metadata" in addition
to the option to provide a custom over-write of doc_ID and block_ID parameters for indexing of text
chunks in the database
"""
from llmware.parsers import Parser, TextParser
from llmware.library import Library
from llmware.retrieval import Query
from llmware.configs import LLMWareConfig
import time
import ast
# All three text databases supported (mongo, postgres, and sqlite)
# if it is highly varied unstructured content, we would recommend Mongo given its flexibility
# if any validation errors with Postgres or SQLite, then we would recommend either further preprocessing the csv or
# ... trying with Mongo
LLMWareConfig().set_active_db("mongo")
def standard_csv_parsing(fp, fn, delimiter=","):
""" Example #1 - This example shows the 'standard' text handler for csv """
# the standard csv parser will interpret the output as a table, trying to preserve the 'row-by-row' and
# 'cell-by-cell' structure (without any keys/labels). There are several options how the output text will
# be aggregated and saved as a single 'text' or 'table' entry:
# --batch_size: this is the number of rows that will be aggregated into each text entry
# e.g., if batch_size == 1, then each row will be a single entry in the database
# if batch_size == 10, then 10 rows will be aggregated into a single 'text' entry in the db
# --interpret_as_table:
# if true, then text will be packaged as a string wrapping a nested list.
# if false, then text will be packaged as a single text stream separated by "\t" between entries
# --optional parameters allow configuration of encoding ('utf-8-sig'), errors ('ignore'),
# and separator ("\n") (applied at end of each row)
# to experiment with the expected output, try the method below, which will not write to the DB, but outputs
# a list in memory
output = TextParser().csv_file_handler(fp,fn,interpret_as_table=False,batch_size=1, delimiter=delimiter)
return output
def standard_csv_parsing_into_library(fp, library_name):
""" Example #2 - building on the first example, this example will parse a set of 'standard' CSV files
directly into the library - if file type is 'tsv' then delimiter automatically applied as '\t' """
# create new library
lib = Library().create_new_library(library_name)
# create parser object, and pass the library to use to write the parsing output
parser = Parser(lib)
# directly call the parse_text method, which will parse text files (csv, tsv, json, jsonl, txt, md)
# this parsed output will be saved to the database by default
output = parser.parse_text(fp, interpret_as_table=False,batch_size=1,delimiter=",", encoding="utf-8-sig",
write_to_db=True)
return output
def configured_csv_parsing(fp, fn,library_name):
""" Example #3 - This example shows how to use mappings for a customized csv """
# metadata is a dictionary mapping of key names to columns in the csv file
# the 'keys' correspond to the keys that will be added to the library
# the 'values' correspond to the columns found in the source CSV (starting with 0 index)
# metadata map must have "text" mapping
# if "doc_ID" or "block_ID" mapping provided, then will "over-write" the default doc_ID and block_ID and
# use the mapping provided in the source CSV
# for all other attributes (e.g., not text, doc_ID, block_ID), the keys will be stored in "special_field1" of
# the database. For Mongo, the keys will be stored directly as a dictionary, while for Postgres and SQLite,
# it will be stored as text string, which must be converted upon use back into a dictionary (see below for
# retrieval example)
# step 1 - create metadata mapping,
# e.g., number indexes map to columns in the csv, 0-index and negative slicing supported (-1 is last column)
metadata = {"text": -1, "doc_ID": 0, "key1": 1, "key2": 2, "key3": 3, "key4": 4}
columns = 6
# step 2 - create library
lib = Library().create_new_library(library_name)
parser = Parser(lib)
# step 3 - invoke parse_csv_config method
# -- note: if file is not comma delimited, then set delimiter
# -- if file is tab delimited, e.g. tsv, then delimiter = "\t"
print("step 1 - parsing")
t0 = time.time()
parser_output = parser.parse_csv_config(fp, fn, cols=columns, mapping_dict=metadata,delimiter=",")
print(f"done parsing - time - {time.time() - t0} - summary - {parser_output}")
return parser_output
def example4_run_query_configured_input(library_name=None, query=""):
""" Example #4 - once the custom csv/tsv is parsed into a Library, it can be used like any other content with the
additional attributes available in special_field1- which can be retrieved as demonstrated below.
-- note: the example below illustrates a 'text_query' but will apply exactly the same for a 'semantic_query'
"""
# run query
lib = Library().load_library(library_name)
q = Query(lib).text_query(query)
for j, results in enumerate(q):
meta = ""
doc_id = -1
# the metadata attributes are saved in the database under "special_field1" column
if "special_field1" in results:
meta = results["special_field1"]
if isinstance(meta, str):
try:
meta = ast.literal_eval(meta)
except:
print(f"could not convert meta string back into dictionary - {meta}")
if "doc_ID" in results:
doc_id = results["doc_ID"]
text = results["text"]
if len(text) > 200:
text = text[0:200]
print(f"\nresults - {j} - query - {query}")
print(f"results - text - {text}")
print(f"results - doc_ID - {doc_id} - metadata - {meta}")
print("done")
return 0