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,202 @@
|
|
|
1
|
+
openapi: 3.0.0
|
|
2
|
+
info:
|
|
3
|
+
title: Example API
|
|
4
|
+
version: 1.0.1
|
|
5
|
+
paths:
|
|
6
|
+
/v1/run:
|
|
7
|
+
post:
|
|
8
|
+
summary: Run a query and get generated text with retrieved passages
|
|
9
|
+
requestBody:
|
|
10
|
+
required: true
|
|
11
|
+
content:
|
|
12
|
+
application/json:
|
|
13
|
+
schema:
|
|
14
|
+
type: object
|
|
15
|
+
properties:
|
|
16
|
+
query:
|
|
17
|
+
type: string
|
|
18
|
+
description: The query string
|
|
19
|
+
result_column:
|
|
20
|
+
type: string
|
|
21
|
+
description: The result column name
|
|
22
|
+
default: generated_texts
|
|
23
|
+
required:
|
|
24
|
+
- query
|
|
25
|
+
responses:
|
|
26
|
+
'200':
|
|
27
|
+
description: Successful response
|
|
28
|
+
content:
|
|
29
|
+
application/json:
|
|
30
|
+
schema:
|
|
31
|
+
type: object
|
|
32
|
+
properties:
|
|
33
|
+
type:
|
|
34
|
+
type: string
|
|
35
|
+
enum:
|
|
36
|
+
- generated_text
|
|
37
|
+
- retrieved_passage
|
|
38
|
+
description: |
|
|
39
|
+
When the type is "generated_text", only "generated_text" is returned.
|
|
40
|
+
The other fields are None. When the type is "retrieved_passage", only
|
|
41
|
+
"retrieved_passage" and "passage_index" are returned. The other fields are None.
|
|
42
|
+
generated_text:
|
|
43
|
+
type: string
|
|
44
|
+
nullable: true
|
|
45
|
+
description: |
|
|
46
|
+
The generated text, only present when "type" is "generated_text".
|
|
47
|
+
retrieved_passage:
|
|
48
|
+
type: object
|
|
49
|
+
nullable: true
|
|
50
|
+
properties:
|
|
51
|
+
content:
|
|
52
|
+
type: string
|
|
53
|
+
doc_id:
|
|
54
|
+
type: string
|
|
55
|
+
filepath:
|
|
56
|
+
type: string
|
|
57
|
+
nullable: true
|
|
58
|
+
file_page:
|
|
59
|
+
type: integer
|
|
60
|
+
nullable: true
|
|
61
|
+
start_idx:
|
|
62
|
+
type: integer
|
|
63
|
+
nullable: true
|
|
64
|
+
end_idx:
|
|
65
|
+
type: integer
|
|
66
|
+
nullable: true
|
|
67
|
+
passage_index:
|
|
68
|
+
type: integer
|
|
69
|
+
nullable: true
|
|
70
|
+
description: |
|
|
71
|
+
The index of the retrieved passage, only present when "type" is "retrieved_passage".
|
|
72
|
+
required:
|
|
73
|
+
- type
|
|
74
|
+
oneOf:
|
|
75
|
+
- required:
|
|
76
|
+
- generated_text
|
|
77
|
+
- required:
|
|
78
|
+
- retrieved_passage
|
|
79
|
+
- passage_index
|
|
80
|
+
/v1/retrieve:
|
|
81
|
+
post:
|
|
82
|
+
summary: Retrieve documents based on a query
|
|
83
|
+
operationId: runRetrieveOnly
|
|
84
|
+
requestBody:
|
|
85
|
+
required: true
|
|
86
|
+
content:
|
|
87
|
+
application/json:
|
|
88
|
+
schema:
|
|
89
|
+
type: object
|
|
90
|
+
properties:
|
|
91
|
+
query:
|
|
92
|
+
type: string
|
|
93
|
+
description: The query string to retrieve documents.
|
|
94
|
+
required:
|
|
95
|
+
- query
|
|
96
|
+
responses:
|
|
97
|
+
'200':
|
|
98
|
+
description: Successful retrieval of documents
|
|
99
|
+
content:
|
|
100
|
+
application/json:
|
|
101
|
+
schema:
|
|
102
|
+
type: object
|
|
103
|
+
properties:
|
|
104
|
+
passages:
|
|
105
|
+
type: array
|
|
106
|
+
items:
|
|
107
|
+
type: object
|
|
108
|
+
properties:
|
|
109
|
+
doc_id:
|
|
110
|
+
type: string
|
|
111
|
+
description: The unique identifier for the document.
|
|
112
|
+
content:
|
|
113
|
+
type: string
|
|
114
|
+
description: The content of the retrieved document.
|
|
115
|
+
score:
|
|
116
|
+
type: number
|
|
117
|
+
format: float
|
|
118
|
+
description: The score of the retrieved document.
|
|
119
|
+
'400':
|
|
120
|
+
description: Invalid request due to missing query parameter
|
|
121
|
+
content:
|
|
122
|
+
application/json:
|
|
123
|
+
schema:
|
|
124
|
+
type: object
|
|
125
|
+
properties:
|
|
126
|
+
error:
|
|
127
|
+
type: string
|
|
128
|
+
description: Error message explaining the issue.
|
|
129
|
+
/v1/stream:
|
|
130
|
+
post:
|
|
131
|
+
summary: Stream generated text with retrieved passages
|
|
132
|
+
description: >
|
|
133
|
+
This endpoint streams the generated text line by line. The `retrieved_passage`
|
|
134
|
+
is sent first, followed by the `result` streamed incrementally.
|
|
135
|
+
requestBody:
|
|
136
|
+
required: true
|
|
137
|
+
content:
|
|
138
|
+
application/json:
|
|
139
|
+
schema:
|
|
140
|
+
type: object
|
|
141
|
+
properties:
|
|
142
|
+
query:
|
|
143
|
+
type: string
|
|
144
|
+
description: The query string
|
|
145
|
+
result_column:
|
|
146
|
+
type: string
|
|
147
|
+
description: The result column name
|
|
148
|
+
default: generated_texts
|
|
149
|
+
required:
|
|
150
|
+
- query
|
|
151
|
+
responses:
|
|
152
|
+
'200':
|
|
153
|
+
description: Successful response with streaming
|
|
154
|
+
content:
|
|
155
|
+
text/event-stream:
|
|
156
|
+
schema:
|
|
157
|
+
type: object
|
|
158
|
+
properties:
|
|
159
|
+
result:
|
|
160
|
+
oneOf:
|
|
161
|
+
- type: string
|
|
162
|
+
- type: array
|
|
163
|
+
items:
|
|
164
|
+
type: string
|
|
165
|
+
description: The result text or list of texts (streamed line by line)
|
|
166
|
+
retrieved_passage:
|
|
167
|
+
type: array
|
|
168
|
+
items:
|
|
169
|
+
type: object
|
|
170
|
+
properties:
|
|
171
|
+
content:
|
|
172
|
+
type: string
|
|
173
|
+
doc_id:
|
|
174
|
+
type: string
|
|
175
|
+
filepath:
|
|
176
|
+
type: string
|
|
177
|
+
nullable: true
|
|
178
|
+
file_page:
|
|
179
|
+
type: integer
|
|
180
|
+
nullable: true
|
|
181
|
+
start_idx:
|
|
182
|
+
type: integer
|
|
183
|
+
nullable: true
|
|
184
|
+
end_idx:
|
|
185
|
+
type: integer
|
|
186
|
+
nullable: true
|
|
187
|
+
|
|
188
|
+
/version:
|
|
189
|
+
get:
|
|
190
|
+
summary: Get the API version
|
|
191
|
+
description: Returns the current version of the API as a string.
|
|
192
|
+
responses:
|
|
193
|
+
'200':
|
|
194
|
+
description: Successful response
|
|
195
|
+
content:
|
|
196
|
+
application/json:
|
|
197
|
+
schema:
|
|
198
|
+
type: object
|
|
199
|
+
properties:
|
|
200
|
+
version:
|
|
201
|
+
type: string
|
|
202
|
+
description: The version of the API
|
|
File without changes
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from random import random
|
|
5
|
+
from typing import List, Union, Dict
|
|
6
|
+
|
|
7
|
+
from llama_index.core.embeddings.mock_embed_model import MockEmbedding
|
|
8
|
+
from llama_index.embeddings.openai import OpenAIEmbedding
|
|
9
|
+
from llama_index.embeddings.openai import OpenAIEmbeddingModelType
|
|
10
|
+
from llama_index.embeddings.ollama import OllamaEmbedding
|
|
11
|
+
from langchain_openai.embeddings import OpenAIEmbeddings
|
|
12
|
+
from llama_index.embeddings.openai_like import OpenAILikeEmbedding
|
|
13
|
+
|
|
14
|
+
from autorag import LazyInit
|
|
15
|
+
from autorag.embedding.vllm import VllmEmbedding
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger("AutoRAG")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class MockEmbeddingRandom(MockEmbedding):
|
|
21
|
+
"""Mock embedding with random vectors."""
|
|
22
|
+
|
|
23
|
+
def _get_vector(self) -> List[float]:
|
|
24
|
+
return [random() for _ in range(self.embed_dim)]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
embedding_models = {
|
|
28
|
+
# llama index
|
|
29
|
+
"openai": LazyInit(
|
|
30
|
+
OpenAIEmbedding
|
|
31
|
+
), # default model is OpenAIEmbeddingModelType.TEXT_EMBED_ADA_002
|
|
32
|
+
"openai_embed_3_large": LazyInit(
|
|
33
|
+
OpenAIEmbedding, model_name=OpenAIEmbeddingModelType.TEXT_EMBED_3_LARGE
|
|
34
|
+
),
|
|
35
|
+
"openai_embed_3_small": LazyInit(
|
|
36
|
+
OpenAIEmbedding, model_name=OpenAIEmbeddingModelType.TEXT_EMBED_3_SMALL
|
|
37
|
+
),
|
|
38
|
+
"mock": LazyInit(MockEmbeddingRandom, embed_dim=768),
|
|
39
|
+
# langchain
|
|
40
|
+
"openai_langchain": LazyInit(OpenAIEmbeddings),
|
|
41
|
+
"ollama": LazyInit(OllamaEmbedding),
|
|
42
|
+
# openai like
|
|
43
|
+
"openai_like": LazyInit(OpenAILikeEmbedding),
|
|
44
|
+
"vllm": LazyInit(VllmEmbedding),
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
# you can use your own model in this way.
|
|
49
|
+
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
|
|
50
|
+
|
|
51
|
+
embedding_models["huggingface_baai_bge_small"] = LazyInit(
|
|
52
|
+
HuggingFaceEmbedding, model_name="BAAI/bge-small-en-v1.5"
|
|
53
|
+
)
|
|
54
|
+
embedding_models["huggingface_cointegrated_rubert_tiny2"] = LazyInit(
|
|
55
|
+
HuggingFaceEmbedding, model_name="cointegrated/rubert-tiny2"
|
|
56
|
+
)
|
|
57
|
+
embedding_models["huggingface_all_mpnet_base_v2"] = LazyInit(
|
|
58
|
+
HuggingFaceEmbedding,
|
|
59
|
+
model_name="sentence-transformers/all-mpnet-base-v2",
|
|
60
|
+
max_length=512,
|
|
61
|
+
)
|
|
62
|
+
embedding_models["huggingface_bge_m3"] = LazyInit(
|
|
63
|
+
HuggingFaceEmbedding, model_name="BAAI/bge-m3"
|
|
64
|
+
)
|
|
65
|
+
embedding_models["huggingface_multilingual_e5_large"] = LazyInit(
|
|
66
|
+
HuggingFaceEmbedding, model_name="intfloat/multilingual-e5-large-instruct"
|
|
67
|
+
)
|
|
68
|
+
except ImportError:
|
|
69
|
+
logger.info(
|
|
70
|
+
"You are using API version of AutoRAG."
|
|
71
|
+
"To use local version, run pip install 'AutoRAG[gpu]'"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class EmbeddingModel:
|
|
76
|
+
@staticmethod
|
|
77
|
+
def load(config: Union[str, Dict, List[Dict]]):
|
|
78
|
+
if isinstance(config, str):
|
|
79
|
+
return EmbeddingModel.load_from_str(config)
|
|
80
|
+
elif isinstance(config, dict):
|
|
81
|
+
return EmbeddingModel.load_from_dict(config)
|
|
82
|
+
elif isinstance(config, list):
|
|
83
|
+
return EmbeddingModel.load_from_list(config)
|
|
84
|
+
else:
|
|
85
|
+
raise ValueError("Invalid type of config")
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def load_from_str(name: str):
|
|
89
|
+
try:
|
|
90
|
+
return embedding_models[name]
|
|
91
|
+
except KeyError:
|
|
92
|
+
raise ValueError(f"Embedding model '{name}' is not supported")
|
|
93
|
+
|
|
94
|
+
@staticmethod
|
|
95
|
+
def load_from_list(option: List[dict]):
|
|
96
|
+
if len(option) != 1:
|
|
97
|
+
raise ValueError("Only one embedding model is supported")
|
|
98
|
+
return EmbeddingModel.load_from_dict(option[0])
|
|
99
|
+
|
|
100
|
+
@staticmethod
|
|
101
|
+
def load_from_dict(option: dict):
|
|
102
|
+
def _check_keys(target: dict):
|
|
103
|
+
if "type" not in target or "model_name" not in target:
|
|
104
|
+
raise ValueError("Both 'type' and 'model_name' must be provided")
|
|
105
|
+
if target["type"] not in [
|
|
106
|
+
"openai",
|
|
107
|
+
"huggingface",
|
|
108
|
+
"mock",
|
|
109
|
+
"ollama",
|
|
110
|
+
"vllm",
|
|
111
|
+
]:
|
|
112
|
+
raise ValueError(
|
|
113
|
+
f"Embedding model type '{target['type']}' is not supported"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def _get_huggingface_class():
|
|
117
|
+
module = sys.modules.get("llama_index.embeddings.huggingface")
|
|
118
|
+
if not module:
|
|
119
|
+
logger.info(
|
|
120
|
+
"You are using API version of AutoRAG. "
|
|
121
|
+
"To use local version, run `pip install 'AutoRAG[gpu]'`."
|
|
122
|
+
)
|
|
123
|
+
return None
|
|
124
|
+
return getattr(module, "HuggingFaceEmbedding", None)
|
|
125
|
+
|
|
126
|
+
_check_keys(option)
|
|
127
|
+
|
|
128
|
+
model_options = option
|
|
129
|
+
model_type = model_options.pop("type")
|
|
130
|
+
|
|
131
|
+
embedding_map = {
|
|
132
|
+
"openai": OpenAIEmbedding,
|
|
133
|
+
"mock": MockEmbeddingRandom,
|
|
134
|
+
"huggingface": _get_huggingface_class(),
|
|
135
|
+
"ollama": OllamaEmbedding,
|
|
136
|
+
"openai_like": OpenAILikeEmbedding,
|
|
137
|
+
"vllm": VllmEmbedding,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
embedding_class = embedding_map.get(model_type)
|
|
141
|
+
if not embedding_class:
|
|
142
|
+
raise ValueError(f"Embedding model type '{model_type}' is not supported")
|
|
143
|
+
|
|
144
|
+
return LazyInit(embedding_class, **model_options)
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
from io import BytesIO
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Any, Dict, List, Optional, Union
|
|
4
|
+
|
|
5
|
+
from llama_index.core.bridge.pydantic import Field, PrivateAttr
|
|
6
|
+
from llama_index.core.callbacks import CallbackManager
|
|
7
|
+
from llama_index.core.embeddings.multi_modal_base import MultiModalEmbedding
|
|
8
|
+
from llama_index.core.schema import ImageType
|
|
9
|
+
from PIL import Image
|
|
10
|
+
from tenacity import retry, stop_after_attempt, wait_exponential
|
|
11
|
+
import atexit
|
|
12
|
+
|
|
13
|
+
SUPPORT_EMBED_TYPES = ["image", "text"]
|
|
14
|
+
logger = logging.getLogger("AutoRAG")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class VllmEmbedding(MultiModalEmbedding):
|
|
18
|
+
"""
|
|
19
|
+
Vllm LLM.
|
|
20
|
+
|
|
21
|
+
This class runs a vLLM embedding model locally.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
tensor_parallel_size: Optional[int] = Field(
|
|
25
|
+
default=1,
|
|
26
|
+
description="The number of GPUs to use for distributed execution with tensor parallelism.",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
trust_remote_code: Optional[bool] = Field(
|
|
30
|
+
default=True,
|
|
31
|
+
description="Trust remote code (e.g., from HuggingFace) when downloading the model and tokenizer.",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
dtype: str = Field(
|
|
35
|
+
default="auto",
|
|
36
|
+
description="The data type for the model weights and activations.",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
download_dir: Optional[str] = Field(
|
|
40
|
+
default=None,
|
|
41
|
+
description="Directory to download and load the weights. (Default to the default cache dir of huggingface)",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
vllm_kwargs: Dict[str, Any] = Field(
|
|
45
|
+
default_factory=dict,
|
|
46
|
+
description="Holds any model parameters valid for `vllm.LLM` call not explicitly specified.",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
retry_cnt: int = 3
|
|
50
|
+
wait_multiplier: int = 1
|
|
51
|
+
wait_min: int = 4
|
|
52
|
+
wait_max: int = 10
|
|
53
|
+
|
|
54
|
+
_client: Any = PrivateAttr()
|
|
55
|
+
|
|
56
|
+
_image_token_id: Union[int, None] = PrivateAttr()
|
|
57
|
+
|
|
58
|
+
def __init__(
|
|
59
|
+
self,
|
|
60
|
+
model_name: str = "facebook/opt-125m",
|
|
61
|
+
embed_batch_size: int = 128,
|
|
62
|
+
tensor_parallel_size: int = 1,
|
|
63
|
+
trust_remote_code: bool = False,
|
|
64
|
+
dtype: str = "auto",
|
|
65
|
+
download_dir: Optional[str] = None,
|
|
66
|
+
vllm_kwargs: Dict[str, Any] = {},
|
|
67
|
+
callback_manager: Optional[CallbackManager] = None,
|
|
68
|
+
) -> None:
|
|
69
|
+
callback_manager = callback_manager or CallbackManager([])
|
|
70
|
+
super().__init__(
|
|
71
|
+
model_name=model_name,
|
|
72
|
+
embed_batch_size=embed_batch_size,
|
|
73
|
+
callback_manager=callback_manager,
|
|
74
|
+
)
|
|
75
|
+
try:
|
|
76
|
+
from vllm import LLM as VLLModel
|
|
77
|
+
except ImportError:
|
|
78
|
+
raise ImportError(
|
|
79
|
+
"Could not import vllm python package. "
|
|
80
|
+
"Please install it with `pip install vllm`."
|
|
81
|
+
)
|
|
82
|
+
self._client = VLLModel(
|
|
83
|
+
model=model_name,
|
|
84
|
+
task="embed",
|
|
85
|
+
max_num_seqs=embed_batch_size,
|
|
86
|
+
tensor_parallel_size=tensor_parallel_size,
|
|
87
|
+
trust_remote_code=trust_remote_code,
|
|
88
|
+
dtype=dtype,
|
|
89
|
+
download_dir=download_dir,
|
|
90
|
+
**vllm_kwargs,
|
|
91
|
+
)
|
|
92
|
+
try:
|
|
93
|
+
self._image_token_id = (
|
|
94
|
+
self._client.llm_engine.model_config.hf_config.image_token_id
|
|
95
|
+
)
|
|
96
|
+
except AttributeError:
|
|
97
|
+
self._image_token_id = None
|
|
98
|
+
|
|
99
|
+
@classmethod
|
|
100
|
+
def class_name(cls) -> str:
|
|
101
|
+
return "VllmEmbedding"
|
|
102
|
+
|
|
103
|
+
@atexit.register
|
|
104
|
+
def close():
|
|
105
|
+
import torch
|
|
106
|
+
import gc
|
|
107
|
+
|
|
108
|
+
if torch.cuda.is_available():
|
|
109
|
+
gc.collect()
|
|
110
|
+
torch.cuda.empty_cache()
|
|
111
|
+
torch.cuda.synchronize()
|
|
112
|
+
|
|
113
|
+
@retry(
|
|
114
|
+
stop=stop_after_attempt(retry_cnt),
|
|
115
|
+
wait=wait_exponential(multiplier=wait_multiplier, min=wait_min, max=wait_max),
|
|
116
|
+
reraise=True,
|
|
117
|
+
)
|
|
118
|
+
def _embed_with_retry(
|
|
119
|
+
self, inputs: List[Union[str, BytesIO]], embed_type: str = "text"
|
|
120
|
+
) -> List[List[float]]:
|
|
121
|
+
"""
|
|
122
|
+
Generates embeddings with retry mechanism.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
inputs: List of texts or images to embed
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
List of embedding vectors
|
|
129
|
+
|
|
130
|
+
Raises:
|
|
131
|
+
Exception: If embedding fails after retries
|
|
132
|
+
|
|
133
|
+
"""
|
|
134
|
+
try:
|
|
135
|
+
if embed_type == "image":
|
|
136
|
+
inputs = [
|
|
137
|
+
{
|
|
138
|
+
"prompt_token_ids": [self._image_token_id],
|
|
139
|
+
"multi_modal_data": {"image": x},
|
|
140
|
+
}
|
|
141
|
+
for x in inputs
|
|
142
|
+
]
|
|
143
|
+
emb = self._client.embed(inputs)
|
|
144
|
+
return [x.outputs.embedding for x in emb]
|
|
145
|
+
except Exception as e:
|
|
146
|
+
logger.warning(f"Embedding attempt failed: {e!s}")
|
|
147
|
+
raise
|
|
148
|
+
|
|
149
|
+
def _embed(
|
|
150
|
+
self, inputs: List[Union[str, BytesIO]], embed_type: str = "text"
|
|
151
|
+
) -> List[List[float]]:
|
|
152
|
+
"""
|
|
153
|
+
Generates Embeddings with input validation and retry mechanism.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
sentences: Texts or Sentences to embed
|
|
157
|
+
prompt_name: The name of the prompt to use for encoding
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
List of embedding vectors
|
|
161
|
+
|
|
162
|
+
Raises:
|
|
163
|
+
ValueError: If any input text is invalid
|
|
164
|
+
Exception: If embedding fails after retries
|
|
165
|
+
|
|
166
|
+
"""
|
|
167
|
+
if embed_type not in SUPPORT_EMBED_TYPES:
|
|
168
|
+
raise (ValueError("Not Implemented"))
|
|
169
|
+
return self._embed_with_retry(inputs, embed_type)
|
|
170
|
+
|
|
171
|
+
def _get_query_embedding(self, query: str) -> List[float]:
|
|
172
|
+
"""
|
|
173
|
+
Generates Embeddings for Query.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
query (str): Query text/sentence
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
List[float]: numpy array of embeddings
|
|
180
|
+
|
|
181
|
+
"""
|
|
182
|
+
return self._embed([query])[0]
|
|
183
|
+
|
|
184
|
+
async def _aget_query_embedding(self, query: str) -> List[float]:
|
|
185
|
+
"""
|
|
186
|
+
Generates Embeddings for Query Asynchronously.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
query (str): Query text/sentence
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
List[float]: numpy array of embeddings
|
|
193
|
+
|
|
194
|
+
"""
|
|
195
|
+
return self._get_query_embedding(query)
|
|
196
|
+
|
|
197
|
+
async def _aget_text_embedding(self, text: str) -> List[float]:
|
|
198
|
+
"""
|
|
199
|
+
Generates Embeddings for text Asynchronously.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
text (str): Text/Sentence
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
List[float]: numpy array of embeddings
|
|
206
|
+
|
|
207
|
+
"""
|
|
208
|
+
return self._get_text_embedding(text)
|
|
209
|
+
|
|
210
|
+
def _get_text_embedding(self, text: str) -> List[float]:
|
|
211
|
+
"""
|
|
212
|
+
Generates Embeddings for text.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
text (str): Text/sentences
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
List[float]: numpy array of embeddings
|
|
219
|
+
|
|
220
|
+
"""
|
|
221
|
+
return self._embed([text])[0]
|
|
222
|
+
|
|
223
|
+
def _get_text_embeddings(self, texts: List[str]) -> List[List[float]]:
|
|
224
|
+
"""
|
|
225
|
+
Generates Embeddings for text.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
texts (List[str]): Texts / Sentences
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
List[List[float]]: numpy array of embeddings
|
|
232
|
+
|
|
233
|
+
"""
|
|
234
|
+
return self._embed(texts)
|
|
235
|
+
|
|
236
|
+
def _get_image_embedding(self, img_file_path: ImageType) -> List[float]:
|
|
237
|
+
"""Generate embedding for an image."""
|
|
238
|
+
image = Image.open(img_file_path)
|
|
239
|
+
return self._embed([image], "image")[0]
|
|
240
|
+
|
|
241
|
+
async def _aget_image_embedding(self, img_file_path: ImageType) -> List[float]:
|
|
242
|
+
"""Generate embedding for an image asynchronously."""
|
|
243
|
+
return self._get_image_embedding(img_file_path)
|
|
244
|
+
|
|
245
|
+
def _get_image_embeddings(
|
|
246
|
+
self, img_file_paths: List[ImageType]
|
|
247
|
+
) -> List[List[float]]:
|
|
248
|
+
images = [Image.open(x) for x in img_file_paths]
|
|
249
|
+
"""Generate embeddings for multiple images."""
|
|
250
|
+
return self._embed(images, "image")
|
|
251
|
+
|
|
252
|
+
async def _aget_image_embeddings(
|
|
253
|
+
self, img_file_paths: List[ImageType]
|
|
254
|
+
) -> List[List[float]]:
|
|
255
|
+
"""Generate embeddings for multiple images asynchronously."""
|
|
256
|
+
return self._get_image_embeddings(img_file_paths)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import warnings
|
|
3
|
+
from typing import List, Callable, Union, Dict
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
from autorag.evaluation.metric.generation import (
|
|
8
|
+
bleu,
|
|
9
|
+
meteor,
|
|
10
|
+
rouge,
|
|
11
|
+
sem_score,
|
|
12
|
+
g_eval,
|
|
13
|
+
bert_score,
|
|
14
|
+
deepeval_faithfulness,
|
|
15
|
+
)
|
|
16
|
+
from autorag.evaluation.util import cast_metrics
|
|
17
|
+
from autorag.schema.metricinput import MetricInput
|
|
18
|
+
|
|
19
|
+
GENERATION_METRIC_FUNC_DICT = {
|
|
20
|
+
func.__name__: func
|
|
21
|
+
for func in [
|
|
22
|
+
bleu,
|
|
23
|
+
meteor,
|
|
24
|
+
rouge,
|
|
25
|
+
sem_score,
|
|
26
|
+
g_eval,
|
|
27
|
+
bert_score,
|
|
28
|
+
deepeval_faithfulness,
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def evaluate_generation(
|
|
34
|
+
metric_inputs: List[MetricInput], metrics: Union[List[str], List[Dict]]
|
|
35
|
+
):
|
|
36
|
+
def decorator_evaluate_generation(func: Callable):
|
|
37
|
+
@functools.wraps(func)
|
|
38
|
+
def wrapper(*args, **kwargs) -> pd.DataFrame:
|
|
39
|
+
generation_result = func(*args, **kwargs)
|
|
40
|
+
if type(generation_result) is tuple:
|
|
41
|
+
assert (
|
|
42
|
+
type(generation_result[0]) is list
|
|
43
|
+
and type(generation_result[0][0]) is str
|
|
44
|
+
), (
|
|
45
|
+
"Input func must return string list as generated answer at the first return value."
|
|
46
|
+
)
|
|
47
|
+
generated_str = generation_result[0]
|
|
48
|
+
elif type(generation_result) is list:
|
|
49
|
+
assert type(generation_result[0]) is str, (
|
|
50
|
+
"Input func must return string list as generated answer at the first return value."
|
|
51
|
+
)
|
|
52
|
+
generated_str = generation_result
|
|
53
|
+
else:
|
|
54
|
+
raise ValueError(
|
|
55
|
+
"Input func must return string list as generated answer at the first return value."
|
|
56
|
+
)
|
|
57
|
+
for metric_input, generated_text in zip(metric_inputs, generated_str):
|
|
58
|
+
metric_input.generated_texts = generated_text
|
|
59
|
+
|
|
60
|
+
metric_scores = {}
|
|
61
|
+
metric_names, metric_params = cast_metrics(metrics)
|
|
62
|
+
|
|
63
|
+
for metric_name, metric_param in zip(metric_names, metric_params):
|
|
64
|
+
if metric_name not in GENERATION_METRIC_FUNC_DICT:
|
|
65
|
+
warnings.warn(
|
|
66
|
+
f"metric {metric_name} is not in supported metrics: {GENERATION_METRIC_FUNC_DICT.keys()}"
|
|
67
|
+
f"{metric_name} will be ignored."
|
|
68
|
+
)
|
|
69
|
+
else:
|
|
70
|
+
metric_scores[metric_name] = GENERATION_METRIC_FUNC_DICT[
|
|
71
|
+
metric_name
|
|
72
|
+
](
|
|
73
|
+
metric_inputs=metric_inputs,
|
|
74
|
+
**metric_param,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
metric_result_df = pd.DataFrame(metric_scores)
|
|
78
|
+
execution_result_df = pd.DataFrame({"generated_texts": generated_str})
|
|
79
|
+
if type(generation_result) is tuple:
|
|
80
|
+
execution_result_df["generated_tokens"] = generation_result[1]
|
|
81
|
+
execution_result_df["generated_log_probs"] = generation_result[2]
|
|
82
|
+
|
|
83
|
+
result_df = pd.concat([execution_result_df, metric_result_df], axis=1)
|
|
84
|
+
return result_df
|
|
85
|
+
|
|
86
|
+
return wrapper
|
|
87
|
+
|
|
88
|
+
return decorator_evaluate_generation
|