AutoRAG 0.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- autorag/__init__.py +82 -0
- autorag/chunker.py +51 -0
- autorag/cli.py +209 -0
- autorag/dashboard.py +199 -0
- autorag/data/__init__.py +109 -0
- autorag/data/chunk/__init__.py +2 -0
- autorag/data/chunk/base.py +128 -0
- autorag/data/chunk/langchain_chunk.py +76 -0
- autorag/data/chunk/llama_index_chunk.py +96 -0
- autorag/data/chunk/run.py +38 -0
- autorag/data/legacy/__init__.py +0 -0
- autorag/data/legacy/corpus/__init__.py +2 -0
- autorag/data/legacy/corpus/langchain.py +47 -0
- autorag/data/legacy/corpus/llama_index.py +93 -0
- autorag/data/legacy/qacreation/__init__.py +6 -0
- autorag/data/legacy/qacreation/base.py +239 -0
- autorag/data/legacy/qacreation/llama_index.py +253 -0
- autorag/data/legacy/qacreation/llama_index_default_prompt.txt +54 -0
- autorag/data/legacy/qacreation/ragas.py +75 -0
- autorag/data/legacy/qacreation/simple.py +99 -0
- autorag/data/parse/__init__.py +1 -0
- autorag/data/parse/base.py +79 -0
- autorag/data/parse/clova.py +194 -0
- autorag/data/parse/langchain_parse.py +87 -0
- autorag/data/parse/llamaparse.py +126 -0
- autorag/data/parse/run.py +141 -0
- autorag/data/parse/table_hybrid_parse.py +134 -0
- autorag/data/qa/__init__.py +3 -0
- autorag/data/qa/evolve/__init__.py +0 -0
- autorag/data/qa/evolve/llama_index_query_evolve.py +64 -0
- autorag/data/qa/evolve/openai_query_evolve.py +81 -0
- autorag/data/qa/evolve/prompt.py +288 -0
- autorag/data/qa/extract_evidence.py +1 -0
- autorag/data/qa/filter/__init__.py +0 -0
- autorag/data/qa/filter/dontknow.py +117 -0
- autorag/data/qa/filter/passage_dependency.py +88 -0
- autorag/data/qa/filter/prompt.py +73 -0
- autorag/data/qa/generation_gt/__init__.py +0 -0
- autorag/data/qa/generation_gt/base.py +16 -0
- autorag/data/qa/generation_gt/llama_index_gen_gt.py +41 -0
- autorag/data/qa/generation_gt/openai_gen_gt.py +84 -0
- autorag/data/qa/generation_gt/prompt.py +27 -0
- autorag/data/qa/query/__init__.py +0 -0
- autorag/data/qa/query/llama_gen_query.py +82 -0
- autorag/data/qa/query/openai_gen_query.py +95 -0
- autorag/data/qa/query/prompt.py +201 -0
- autorag/data/qa/sample.py +26 -0
- autorag/data/qa/schema.py +322 -0
- autorag/data/utils/__init__.py +0 -0
- autorag/data/utils/util.py +103 -0
- autorag/deploy/__init__.py +9 -0
- autorag/deploy/api.py +303 -0
- autorag/deploy/base.py +235 -0
- autorag/deploy/gradio.py +74 -0
- autorag/deploy/swagger.yml +202 -0
- autorag/embedding/__init__.py +0 -0
- autorag/embedding/base.py +144 -0
- autorag/embedding/vllm.py +256 -0
- autorag/evaluation/__init__.py +3 -0
- autorag/evaluation/generation.py +88 -0
- autorag/evaluation/metric/__init__.py +22 -0
- autorag/evaluation/metric/deepeval_prompt.py +322 -0
- autorag/evaluation/metric/g_eval_prompts/coh_detailed.txt +32 -0
- autorag/evaluation/metric/g_eval_prompts/con_detailed.txt +33 -0
- autorag/evaluation/metric/g_eval_prompts/flu_detailed.txt +26 -0
- autorag/evaluation/metric/g_eval_prompts/rel_detailed.txt +33 -0
- autorag/evaluation/metric/generation.py +504 -0
- autorag/evaluation/metric/retrieval.py +115 -0
- autorag/evaluation/metric/retrieval_contents.py +65 -0
- autorag/evaluation/metric/util.py +88 -0
- autorag/evaluation/retrieval.py +83 -0
- autorag/evaluation/retrieval_contents.py +65 -0
- autorag/evaluation/util.py +43 -0
- autorag/evaluator.py +559 -0
- autorag/node_line.py +65 -0
- autorag/nodes/__init__.py +0 -0
- autorag/nodes/generator/__init__.py +4 -0
- autorag/nodes/generator/base.py +103 -0
- autorag/nodes/generator/llama_index_llm.py +169 -0
- autorag/nodes/generator/openai_llm.py +329 -0
- autorag/nodes/generator/run.py +148 -0
- autorag/nodes/generator/vllm.py +147 -0
- autorag/nodes/generator/vllm_api.py +191 -0
- autorag/nodes/hybridretrieval/__init__.py +2 -0
- autorag/nodes/hybridretrieval/base.py +58 -0
- autorag/nodes/hybridretrieval/hybrid_cc.py +227 -0
- autorag/nodes/hybridretrieval/hybrid_rrf.py +149 -0
- autorag/nodes/hybridretrieval/run.py +137 -0
- autorag/nodes/lexicalretrieval/__init__.py +1 -0
- autorag/nodes/lexicalretrieval/bm25.py +381 -0
- autorag/nodes/lexicalretrieval/run.py +148 -0
- autorag/nodes/passageaugmenter/__init__.py +2 -0
- autorag/nodes/passageaugmenter/base.py +76 -0
- autorag/nodes/passageaugmenter/pass_passage_augmenter.py +43 -0
- autorag/nodes/passageaugmenter/prev_next_augmenter.py +155 -0
- autorag/nodes/passageaugmenter/run.py +131 -0
- autorag/nodes/passagecompressor/__init__.py +4 -0
- autorag/nodes/passagecompressor/base.py +78 -0
- autorag/nodes/passagecompressor/longllmlingua.py +115 -0
- autorag/nodes/passagecompressor/pass_compressor.py +16 -0
- autorag/nodes/passagecompressor/refine.py +54 -0
- autorag/nodes/passagecompressor/run.py +186 -0
- autorag/nodes/passagecompressor/tree_summarize.py +56 -0
- autorag/nodes/passagefilter/__init__.py +6 -0
- autorag/nodes/passagefilter/base.py +40 -0
- autorag/nodes/passagefilter/pass_passage_filter.py +14 -0
- autorag/nodes/passagefilter/percentile_cutoff.py +58 -0
- autorag/nodes/passagefilter/recency.py +105 -0
- autorag/nodes/passagefilter/run.py +138 -0
- autorag/nodes/passagefilter/similarity_percentile_cutoff.py +134 -0
- autorag/nodes/passagefilter/similarity_threshold_cutoff.py +112 -0
- autorag/nodes/passagefilter/threshold_cutoff.py +78 -0
- autorag/nodes/passagereranker/__init__.py +16 -0
- autorag/nodes/passagereranker/base.py +44 -0
- autorag/nodes/passagereranker/cohere.py +118 -0
- autorag/nodes/passagereranker/colbert.py +213 -0
- autorag/nodes/passagereranker/flag_embedding.py +112 -0
- autorag/nodes/passagereranker/flag_embedding_llm.py +101 -0
- autorag/nodes/passagereranker/flashrank.py +245 -0
- autorag/nodes/passagereranker/jina.py +115 -0
- autorag/nodes/passagereranker/koreranker.py +136 -0
- autorag/nodes/passagereranker/mixedbreadai.py +126 -0
- autorag/nodes/passagereranker/monot5.py +190 -0
- autorag/nodes/passagereranker/openvino.py +191 -0
- autorag/nodes/passagereranker/pass_reranker.py +31 -0
- autorag/nodes/passagereranker/rankgpt.py +170 -0
- autorag/nodes/passagereranker/run.py +145 -0
- autorag/nodes/passagereranker/sentence_transformer.py +129 -0
- autorag/nodes/passagereranker/tart/__init__.py +1 -0
- autorag/nodes/passagereranker/tart/modeling_enc_t5.py +152 -0
- autorag/nodes/passagereranker/tart/tart.py +139 -0
- autorag/nodes/passagereranker/tart/tokenization_enc_t5.py +112 -0
- autorag/nodes/passagereranker/time_reranker.py +72 -0
- autorag/nodes/passagereranker/upr.py +160 -0
- autorag/nodes/passagereranker/voyageai.py +109 -0
- autorag/nodes/promptmaker/__init__.py +12 -0
- autorag/nodes/promptmaker/base.py +32 -0
- autorag/nodes/promptmaker/chat_fstring.py +73 -0
- autorag/nodes/promptmaker/fstring.py +49 -0
- autorag/nodes/promptmaker/long_context_reorder.py +83 -0
- autorag/nodes/promptmaker/run.py +283 -0
- autorag/nodes/promptmaker/window_replacement.py +85 -0
- autorag/nodes/queryexpansion/__init__.py +4 -0
- autorag/nodes/queryexpansion/base.py +62 -0
- autorag/nodes/queryexpansion/hyde.py +43 -0
- autorag/nodes/queryexpansion/multi_query_expansion.py +57 -0
- autorag/nodes/queryexpansion/pass_query_expansion.py +22 -0
- autorag/nodes/queryexpansion/query_decompose.py +111 -0
- autorag/nodes/queryexpansion/run.py +308 -0
- autorag/nodes/retrieval/__init__.py +0 -0
- autorag/nodes/retrieval/base.py +127 -0
- autorag/nodes/retrieval/run_util.py +152 -0
- autorag/nodes/semanticretrieval/__init__.py +1 -0
- autorag/nodes/semanticretrieval/run.py +148 -0
- autorag/nodes/semanticretrieval/vectordb.py +339 -0
- autorag/nodes/util.py +16 -0
- autorag/parser.py +37 -0
- autorag/schema/__init__.py +3 -0
- autorag/schema/base.py +35 -0
- autorag/schema/metricinput.py +99 -0
- autorag/schema/module.py +24 -0
- autorag/schema/node.py +144 -0
- autorag/strategy.py +165 -0
- autorag/support.py +235 -0
- autorag/utils/__init__.py +8 -0
- autorag/utils/cast.py +45 -0
- autorag/utils/preprocess.py +149 -0
- autorag/utils/util.py +759 -0
- autorag/validator.py +98 -0
- autorag/vectordb/__init__.py +75 -0
- autorag/vectordb/base.py +73 -0
- autorag/vectordb/chroma.py +118 -0
- autorag/vectordb/couchbase.py +239 -0
- autorag/vectordb/milvus.py +169 -0
- autorag/vectordb/pinecone.py +121 -0
- autorag/vectordb/qdrant.py +155 -0
- autorag/vectordb/weaviate.py +184 -0
- autorag/web.py +81 -0
- autorag-0.0.0.dist-info/METADATA +780 -0
- autorag-0.0.0.dist-info/RECORD +184 -0
- autorag-0.0.0.dist-info/WHEEL +5 -0
- autorag-0.0.0.dist-info/entry_points.txt +2 -0
- autorag-0.0.0.dist-info/licenses/LICENSE +201 -0
- autorag-0.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Tuple, List, Dict, Any
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
from autorag.embedding.base import EmbeddingModel
|
|
8
|
+
from autorag.data import chunk_modules, sentence_splitter_modules
|
|
9
|
+
from autorag.utils import result_to_dataframe
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger("AutoRAG")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def chunker_node(func):
|
|
15
|
+
@functools.wraps(func)
|
|
16
|
+
@result_to_dataframe(["doc_id", "contents", "path", "start_end_idx", "metadata"])
|
|
17
|
+
def wrapper(
|
|
18
|
+
parsed_result: pd.DataFrame, chunk_method: str, **kwargs
|
|
19
|
+
) -> Tuple[
|
|
20
|
+
List[str], List[str], List[str], List[Tuple[int, int]], List[Dict[str, Any]]
|
|
21
|
+
]:
|
|
22
|
+
logger.info(f"Running chunker - {func.__name__} module...")
|
|
23
|
+
|
|
24
|
+
# get texts from parsed_result
|
|
25
|
+
texts = parsed_result["texts"].tolist()
|
|
26
|
+
|
|
27
|
+
# get filenames from parsed_result when 'add_file_name' is setting
|
|
28
|
+
file_name_language = kwargs.pop("add_file_name", None)
|
|
29
|
+
metadata_list = make_metadata_list(parsed_result)
|
|
30
|
+
|
|
31
|
+
# run chunk module
|
|
32
|
+
if func.__name__ in ["llama_index_chunk", "langchain_chunk"]:
|
|
33
|
+
chunk_instance = __get_chunk_instance(
|
|
34
|
+
func.__name__, chunk_method.lower(), **kwargs
|
|
35
|
+
)
|
|
36
|
+
result = func(
|
|
37
|
+
texts=texts,
|
|
38
|
+
chunker=chunk_instance,
|
|
39
|
+
file_name_language=file_name_language,
|
|
40
|
+
metadata_list=metadata_list,
|
|
41
|
+
)
|
|
42
|
+
del chunk_instance
|
|
43
|
+
return result
|
|
44
|
+
else:
|
|
45
|
+
raise ValueError(f"Unsupported module_type: {func.__name__}")
|
|
46
|
+
|
|
47
|
+
return wrapper
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def make_metadata_list(parsed_result: pd.DataFrame) -> List[Dict[str, str]]:
|
|
51
|
+
metadata_list = [{} for _ in range(len(parsed_result["texts"]))]
|
|
52
|
+
|
|
53
|
+
def _make_metadata_pure(
|
|
54
|
+
lst: List[str], key: str, metadata_lst: List[Dict[str, str]]
|
|
55
|
+
):
|
|
56
|
+
for value, metadata in zip(lst, metadata_lst):
|
|
57
|
+
metadata[key] = value
|
|
58
|
+
|
|
59
|
+
for column in ["page", "last_modified_datetime", "path"]:
|
|
60
|
+
if column in parsed_result.columns:
|
|
61
|
+
_make_metadata_pure(parsed_result[column].tolist(), column, metadata_list)
|
|
62
|
+
return metadata_list
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def __get_chunk_instance(module_type: str, chunk_method: str, **kwargs):
|
|
66
|
+
# Add sentence_splitter to kwargs
|
|
67
|
+
sentence_available_methods = [
|
|
68
|
+
"semantic_llama_index",
|
|
69
|
+
"semanticdoublemerging",
|
|
70
|
+
"sentencewindow",
|
|
71
|
+
]
|
|
72
|
+
if chunk_method in sentence_available_methods:
|
|
73
|
+
# llama index default sentence_splitter is 'nltk -PunktSentenceTokenizer'
|
|
74
|
+
if "sentence_splitter" in kwargs.keys():
|
|
75
|
+
sentence_splitter_str = kwargs.pop("sentence_splitter")
|
|
76
|
+
sentence_splitter_func = sentence_splitter_modules[sentence_splitter_str]()
|
|
77
|
+
kwargs.update({"sentence_splitter": sentence_splitter_func})
|
|
78
|
+
|
|
79
|
+
def get_embedding_model(_embed_model_str: str, _module_type: str):
|
|
80
|
+
if _embed_model_str == "openai":
|
|
81
|
+
if _module_type == "langchain_chunk":
|
|
82
|
+
_embed_model_str = "openai_langchain"
|
|
83
|
+
return EmbeddingModel.load(_embed_model_str)()
|
|
84
|
+
|
|
85
|
+
# Add embed_model to kwargs
|
|
86
|
+
embedding_available_methods = ["semantic_llama_index", "semantic_langchain"]
|
|
87
|
+
if chunk_method in embedding_available_methods:
|
|
88
|
+
# there is no default embed_model, so we have to get it parameter and add it.
|
|
89
|
+
if "embed_model" not in kwargs.keys():
|
|
90
|
+
raise ValueError(f"embed_model is required for {chunk_method} method.")
|
|
91
|
+
embed_model_str = kwargs.pop("embed_model")
|
|
92
|
+
embed_model = get_embedding_model(embed_model_str, module_type)
|
|
93
|
+
if chunk_method == "semantic_llama_index":
|
|
94
|
+
kwargs.update({"embed_model": embed_model})
|
|
95
|
+
elif chunk_method == "semantic_langchain":
|
|
96
|
+
kwargs.update({"embeddings": embed_model})
|
|
97
|
+
|
|
98
|
+
return chunk_modules[chunk_method](**kwargs)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def add_file_name(
|
|
102
|
+
file_name_language: str, file_names: List[str], chunk_texts: List[str]
|
|
103
|
+
) -> List[str]:
|
|
104
|
+
if file_name_language == "en":
|
|
105
|
+
return list(
|
|
106
|
+
map(
|
|
107
|
+
lambda x: f"file_name: {x[1]}\n contents: {x[0]}",
|
|
108
|
+
zip(chunk_texts, file_names),
|
|
109
|
+
)
|
|
110
|
+
)
|
|
111
|
+
elif file_name_language == "ko":
|
|
112
|
+
return list(
|
|
113
|
+
map(
|
|
114
|
+
lambda x: f"파일 제목: {x[1]}\n 내용: {x[0]}",
|
|
115
|
+
zip(chunk_texts, file_names),
|
|
116
|
+
)
|
|
117
|
+
)
|
|
118
|
+
elif file_name_language == "ja":
|
|
119
|
+
return list(
|
|
120
|
+
map(
|
|
121
|
+
lambda x: f"ファイル名: {x[1]}\n 内容: {x[0]}",
|
|
122
|
+
zip(chunk_texts, file_names),
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
else:
|
|
126
|
+
raise ValueError(
|
|
127
|
+
f"Unsupported file_name_language: {file_name_language}. Choose from 'en' ,'ko' or 'ja."
|
|
128
|
+
)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from itertools import chain
|
|
3
|
+
import uuid
|
|
4
|
+
from typing import Tuple, List, Dict, Any, Optional
|
|
5
|
+
|
|
6
|
+
from langchain_text_splitters import TextSplitter
|
|
7
|
+
|
|
8
|
+
from autorag.data.chunk.base import chunker_node, add_file_name
|
|
9
|
+
from autorag.data.utils.util import add_essential_metadata, get_start_end_idx
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@chunker_node
|
|
13
|
+
def langchain_chunk(
|
|
14
|
+
texts: List[str],
|
|
15
|
+
chunker: TextSplitter,
|
|
16
|
+
file_name_language: Optional[str] = None,
|
|
17
|
+
metadata_list: Optional[List[Dict[str, str]]] = None,
|
|
18
|
+
) -> Tuple[
|
|
19
|
+
List[str], List[str], List[str], List[Tuple[int, int]], List[Dict[str, Any]]
|
|
20
|
+
]:
|
|
21
|
+
"""
|
|
22
|
+
Chunk texts from the parsed result to use langchain chunk method
|
|
23
|
+
|
|
24
|
+
:param texts: The list of texts to chunk from the parsed result
|
|
25
|
+
:param chunker: A langchain TextSplitter(Chunker) instance.
|
|
26
|
+
:param file_name_language: The language to use 'add_file_name' feature.
|
|
27
|
+
You need to set one of 'English' and 'Korean'
|
|
28
|
+
The 'add_file_name' feature is to add a file_name to chunked_contents.
|
|
29
|
+
This is used to prevent hallucination by retrieving contents from the wrong document.
|
|
30
|
+
Default form of 'English' is "file_name: {file_name}\n contents: {content}"
|
|
31
|
+
:param metadata_list: The list of dict of metadata from the parsed result
|
|
32
|
+
:return: tuple of lists containing the chunked doc_id, contents, path, start_idx, end_idx and metadata
|
|
33
|
+
"""
|
|
34
|
+
results = [
|
|
35
|
+
langchain_chunk_pure(text, chunker, file_name_language, meta)
|
|
36
|
+
for text, meta in zip(texts, metadata_list)
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
doc_id, contents, path, start_end_idx, metadata = (
|
|
40
|
+
list(chain.from_iterable(item)) for item in zip(*results)
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
return doc_id, contents, path, start_end_idx, metadata
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def langchain_chunk_pure(
|
|
47
|
+
text: str,
|
|
48
|
+
chunker: TextSplitter,
|
|
49
|
+
file_name_language: Optional[str] = None,
|
|
50
|
+
_metadata: Optional[Dict[str, str]] = None,
|
|
51
|
+
):
|
|
52
|
+
# chunk
|
|
53
|
+
chunk_results = chunker.create_documents([text], metadatas=[_metadata])
|
|
54
|
+
|
|
55
|
+
# make doc_id
|
|
56
|
+
doc_id = list(str(uuid.uuid4()) for _ in range(len(chunk_results)))
|
|
57
|
+
|
|
58
|
+
# make path
|
|
59
|
+
path_lst = list(map(lambda x: x.metadata.get("path", ""), chunk_results))
|
|
60
|
+
|
|
61
|
+
# make contents and start_end_idx
|
|
62
|
+
if file_name_language:
|
|
63
|
+
chunked_file_names = list(map(lambda x: os.path.basename(x), path_lst))
|
|
64
|
+
chunked_texts = list(map(lambda x: x.page_content, chunk_results))
|
|
65
|
+
start_end_idx = list(map(lambda x: get_start_end_idx(text, x), chunked_texts))
|
|
66
|
+
contents = add_file_name(file_name_language, chunked_file_names, chunked_texts)
|
|
67
|
+
else:
|
|
68
|
+
contents = list(map(lambda node: node.page_content, chunk_results))
|
|
69
|
+
start_end_idx = list(map(lambda x: get_start_end_idx(text, x), contents))
|
|
70
|
+
|
|
71
|
+
# make metadata
|
|
72
|
+
metadata = list(
|
|
73
|
+
map(lambda node: add_essential_metadata(node.metadata), chunk_results)
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
return doc_id, contents, path_lst, start_end_idx, metadata
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import os.path
|
|
2
|
+
from itertools import chain
|
|
3
|
+
from typing import Tuple, List, Dict, Any, Optional
|
|
4
|
+
|
|
5
|
+
from llama_index.core import Document
|
|
6
|
+
from llama_index.core.node_parser.interface import NodeParser
|
|
7
|
+
|
|
8
|
+
from autorag.utils.util import process_batch, get_event_loop
|
|
9
|
+
from autorag.data.chunk.base import chunker_node, add_file_name
|
|
10
|
+
from autorag.data.utils.util import (
|
|
11
|
+
add_essential_metadata_llama_text_node,
|
|
12
|
+
get_start_end_idx,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@chunker_node
|
|
17
|
+
def llama_index_chunk(
|
|
18
|
+
texts: List[str],
|
|
19
|
+
chunker: NodeParser,
|
|
20
|
+
file_name_language: Optional[str] = None,
|
|
21
|
+
metadata_list: Optional[List[Dict[str, str]]] = None,
|
|
22
|
+
batch: int = 8,
|
|
23
|
+
) -> Tuple[
|
|
24
|
+
List[str], List[str], List[str], List[Tuple[int, int]], List[Dict[str, Any]]
|
|
25
|
+
]:
|
|
26
|
+
"""
|
|
27
|
+
Chunk texts from the parsed result to use llama index chunk method
|
|
28
|
+
|
|
29
|
+
:param texts: The list of texts to chunk from the parsed result
|
|
30
|
+
:param chunker: A llama index NodeParser(Chunker) instance.
|
|
31
|
+
:param file_name_language: The language to use 'add_file_name' feature.
|
|
32
|
+
You need to set one of 'English' and 'Korean'
|
|
33
|
+
The 'add_file_name' feature is to add a file_name to chunked_contents.
|
|
34
|
+
This is used to prevent hallucination by retrieving contents from the wrong document.
|
|
35
|
+
Default form of 'English' is "file_name: {file_name}\n contents: {content}"
|
|
36
|
+
:param metadata_list: The list of dict of metadata from the parsed result
|
|
37
|
+
:param batch: The batch size for chunk texts. Default is 8
|
|
38
|
+
:return: tuple of lists containing the chunked doc_id, contents, path, start_idx, end_idx and metadata
|
|
39
|
+
"""
|
|
40
|
+
tasks = [
|
|
41
|
+
llama_index_chunk_pure(text, chunker, file_name_language, meta)
|
|
42
|
+
for text, meta in zip(texts, metadata_list)
|
|
43
|
+
]
|
|
44
|
+
loop = get_event_loop()
|
|
45
|
+
results = loop.run_until_complete(process_batch(tasks, batch))
|
|
46
|
+
|
|
47
|
+
doc_id, contents, path, start_end_idx, metadata = (
|
|
48
|
+
list(chain.from_iterable(item)) for item in zip(*results)
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
return list(doc_id), list(contents), list(path), list(start_end_idx), list(metadata)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
async def llama_index_chunk_pure(
|
|
55
|
+
text: str,
|
|
56
|
+
chunker: NodeParser,
|
|
57
|
+
file_name_language: Optional[str] = None,
|
|
58
|
+
_metadata: Optional[Dict[str, str]] = None,
|
|
59
|
+
):
|
|
60
|
+
# set document
|
|
61
|
+
document = [Document(text=text, metadata=_metadata)]
|
|
62
|
+
|
|
63
|
+
# chunk document
|
|
64
|
+
chunk_results = await chunker.aget_nodes_from_documents(documents=document)
|
|
65
|
+
|
|
66
|
+
# make doc_id
|
|
67
|
+
doc_id = list(map(lambda node: node.node_id, chunk_results))
|
|
68
|
+
|
|
69
|
+
# make path
|
|
70
|
+
path_lst = list(map(lambda x: x.metadata.get("path", ""), chunk_results))
|
|
71
|
+
|
|
72
|
+
# make contents and start_end_idx
|
|
73
|
+
if file_name_language:
|
|
74
|
+
chunked_file_names = list(map(lambda x: os.path.basename(x), path_lst))
|
|
75
|
+
chunked_texts = list(map(lambda x: x.text, chunk_results))
|
|
76
|
+
start_end_idx = list(
|
|
77
|
+
map(
|
|
78
|
+
lambda x: get_start_end_idx(text, x),
|
|
79
|
+
chunked_texts,
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
contents = add_file_name(file_name_language, chunked_file_names, chunked_texts)
|
|
83
|
+
else:
|
|
84
|
+
contents = list(map(lambda x: x.text, chunk_results))
|
|
85
|
+
start_end_idx = list(map(lambda x: get_start_end_idx(text, x), contents))
|
|
86
|
+
|
|
87
|
+
metadata = list(
|
|
88
|
+
map(
|
|
89
|
+
lambda node: add_essential_metadata_llama_text_node(
|
|
90
|
+
node.metadata, node.relationships
|
|
91
|
+
),
|
|
92
|
+
chunk_results,
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
return doc_id, contents, path_lst, start_end_idx, metadata
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Callable, List, Dict
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
from autorag.strategy import measure_speed
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def run_chunker(
|
|
9
|
+
modules: List[Callable],
|
|
10
|
+
module_params: List[Dict],
|
|
11
|
+
parsed_result: pd.DataFrame,
|
|
12
|
+
project_dir: str,
|
|
13
|
+
):
|
|
14
|
+
results, execution_times = zip(
|
|
15
|
+
*map(
|
|
16
|
+
lambda x: measure_speed(x[0], parsed_result=parsed_result, **x[1]),
|
|
17
|
+
zip(modules, module_params),
|
|
18
|
+
)
|
|
19
|
+
)
|
|
20
|
+
average_times = list(map(lambda x: x / len(results[0]), execution_times))
|
|
21
|
+
|
|
22
|
+
# save results to parquet files
|
|
23
|
+
filepaths = list(
|
|
24
|
+
map(lambda x: os.path.join(project_dir, f"{x}.parquet"), range(len(modules)))
|
|
25
|
+
)
|
|
26
|
+
list(map(lambda x: x[0].to_parquet(x[1], index=False), zip(results, filepaths)))
|
|
27
|
+
filenames = list(map(lambda x: os.path.basename(x), filepaths))
|
|
28
|
+
|
|
29
|
+
summary_df = pd.DataFrame(
|
|
30
|
+
{
|
|
31
|
+
"filename": filenames,
|
|
32
|
+
"module_name": list(map(lambda module: module.__name__, modules)),
|
|
33
|
+
"module_params": module_params,
|
|
34
|
+
"execution_time": average_times,
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
summary_df.to_csv(os.path.join(project_dir, "summary.csv"), index=False)
|
|
38
|
+
return summary_df
|
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
from typing import List, Optional
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
from langchain_core.documents import Document
|
|
6
|
+
|
|
7
|
+
from autorag.data.utils.util import add_essential_metadata
|
|
8
|
+
from autorag.utils.util import save_parquet_safe
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def langchain_documents_to_parquet(
|
|
12
|
+
langchain_documents: List[Document],
|
|
13
|
+
output_filepath: Optional[str] = None,
|
|
14
|
+
upsert: bool = False,
|
|
15
|
+
) -> pd.DataFrame:
|
|
16
|
+
"""
|
|
17
|
+
Langchain documents to corpus dataframe.
|
|
18
|
+
Corpus dataframe will be saved to filepath(file_dir/filename) if given.
|
|
19
|
+
Return corpus dataframe whether the filepath is given.
|
|
20
|
+
You can use this method to create corpus.parquet after load and chunk using Llama Index.
|
|
21
|
+
|
|
22
|
+
:param langchain_documents: List of langchain documents.
|
|
23
|
+
:param output_filepath: Optional filepath to save the parquet file.
|
|
24
|
+
If None, the function will return the processed_data as pd.DataFrame, but do not save as parquet.
|
|
25
|
+
File directory must exist. File extension must be .parquet
|
|
26
|
+
:param upsert: If true, the function will overwrite the existing file if it exists.
|
|
27
|
+
Default is False.
|
|
28
|
+
:return: Corpus data as pd.DataFrame
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
corpus_df = pd.DataFrame(
|
|
32
|
+
list(
|
|
33
|
+
map(
|
|
34
|
+
lambda doc: {
|
|
35
|
+
"doc_id": str(uuid.uuid4()),
|
|
36
|
+
"contents": doc.page_content,
|
|
37
|
+
"metadata": add_essential_metadata(doc.metadata),
|
|
38
|
+
},
|
|
39
|
+
langchain_documents,
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
if output_filepath is not None:
|
|
45
|
+
save_parquet_safe(corpus_df, output_filepath, upsert=upsert)
|
|
46
|
+
|
|
47
|
+
return corpus_df
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
from typing import List, Optional
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
from llama_index.core import Document
|
|
6
|
+
from llama_index.core.schema import TextNode
|
|
7
|
+
|
|
8
|
+
from autorag.data.utils.util import (
|
|
9
|
+
add_essential_metadata,
|
|
10
|
+
add_essential_metadata_llama_text_node,
|
|
11
|
+
)
|
|
12
|
+
from autorag.utils.util import save_parquet_safe
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def llama_documents_to_parquet(
|
|
16
|
+
llama_documents: List[Document],
|
|
17
|
+
output_filepath: Optional[str] = None,
|
|
18
|
+
upsert: bool = False,
|
|
19
|
+
) -> pd.DataFrame:
|
|
20
|
+
"""
|
|
21
|
+
Llama Index documents to corpus dataframe.
|
|
22
|
+
Corpus dataframe will be saved to filepath(file_dir/filename) if given.
|
|
23
|
+
Return corpus dataframe whether the filepath is given.
|
|
24
|
+
You can use this method to create corpus.parquet after load and chunk using Llama Index.
|
|
25
|
+
|
|
26
|
+
:param llama_documents: List[Document]
|
|
27
|
+
:param output_filepath: Optional filepath to save the parquet file.
|
|
28
|
+
If None, the function will return the processed_data as pd.DataFrame, but do not save as parquet.
|
|
29
|
+
File directory must exist. File extension must be .parquet
|
|
30
|
+
:param upsert: If true, the function will overwrite the existing file if it exists.
|
|
31
|
+
Default is False.
|
|
32
|
+
:return: Corpus data as pd.DataFrame
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
doc_lst = pd.DataFrame(
|
|
36
|
+
list(
|
|
37
|
+
map(
|
|
38
|
+
lambda doc: {
|
|
39
|
+
"doc_id": str(uuid.uuid4()),
|
|
40
|
+
"contents": doc.text,
|
|
41
|
+
"metadata": add_essential_metadata(doc.metadata),
|
|
42
|
+
},
|
|
43
|
+
llama_documents,
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
processed_df = pd.DataFrame(doc_lst)
|
|
49
|
+
|
|
50
|
+
if output_filepath is not None:
|
|
51
|
+
save_parquet_safe(processed_df, output_filepath, upsert=upsert)
|
|
52
|
+
|
|
53
|
+
return processed_df
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def llama_text_node_to_parquet(
|
|
57
|
+
text_nodes: List[TextNode],
|
|
58
|
+
output_filepath: Optional[str] = None,
|
|
59
|
+
upsert: bool = False,
|
|
60
|
+
) -> pd.DataFrame:
|
|
61
|
+
"""
|
|
62
|
+
Llama Index text nodes to corpus dataframe.
|
|
63
|
+
Corpus dataframe will be saved to filepath(file_dir/filename) if given.
|
|
64
|
+
Return corpus dataframe whether the filepath is given.
|
|
65
|
+
You can use this method to create corpus.parquet after load and chunk using Llama Index.
|
|
66
|
+
|
|
67
|
+
:param text_nodes: List of llama index text nodes.
|
|
68
|
+
:param output_filepath: Optional filepath to save the parquet file.
|
|
69
|
+
If None, the function will return the processed_data as pd.DataFrame, but do not save as parquet.
|
|
70
|
+
File directory must exist. File extension must be .parquet
|
|
71
|
+
:param upsert: If true, the function will overwrite the existing file if it exists.
|
|
72
|
+
Default is False.
|
|
73
|
+
:return: Corpus data as pd.DataFrame
|
|
74
|
+
"""
|
|
75
|
+
corpus_df = pd.DataFrame(
|
|
76
|
+
list(
|
|
77
|
+
map(
|
|
78
|
+
lambda node: {
|
|
79
|
+
"doc_id": node.node_id,
|
|
80
|
+
"contents": node.text,
|
|
81
|
+
"metadata": add_essential_metadata_llama_text_node(
|
|
82
|
+
node.metadata, node.relationships
|
|
83
|
+
),
|
|
84
|
+
},
|
|
85
|
+
text_nodes,
|
|
86
|
+
)
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
if output_filepath is not None:
|
|
91
|
+
save_parquet_safe(corpus_df, output_filepath, upsert=upsert)
|
|
92
|
+
|
|
93
|
+
return corpus_df
|