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.
Files changed (184) hide show
  1. autorag/__init__.py +82 -0
  2. autorag/chunker.py +51 -0
  3. autorag/cli.py +209 -0
  4. autorag/dashboard.py +199 -0
  5. autorag/data/__init__.py +109 -0
  6. autorag/data/chunk/__init__.py +2 -0
  7. autorag/data/chunk/base.py +128 -0
  8. autorag/data/chunk/langchain_chunk.py +76 -0
  9. autorag/data/chunk/llama_index_chunk.py +96 -0
  10. autorag/data/chunk/run.py +38 -0
  11. autorag/data/legacy/__init__.py +0 -0
  12. autorag/data/legacy/corpus/__init__.py +2 -0
  13. autorag/data/legacy/corpus/langchain.py +47 -0
  14. autorag/data/legacy/corpus/llama_index.py +93 -0
  15. autorag/data/legacy/qacreation/__init__.py +6 -0
  16. autorag/data/legacy/qacreation/base.py +239 -0
  17. autorag/data/legacy/qacreation/llama_index.py +253 -0
  18. autorag/data/legacy/qacreation/llama_index_default_prompt.txt +54 -0
  19. autorag/data/legacy/qacreation/ragas.py +75 -0
  20. autorag/data/legacy/qacreation/simple.py +99 -0
  21. autorag/data/parse/__init__.py +1 -0
  22. autorag/data/parse/base.py +79 -0
  23. autorag/data/parse/clova.py +194 -0
  24. autorag/data/parse/langchain_parse.py +87 -0
  25. autorag/data/parse/llamaparse.py +126 -0
  26. autorag/data/parse/run.py +141 -0
  27. autorag/data/parse/table_hybrid_parse.py +134 -0
  28. autorag/data/qa/__init__.py +3 -0
  29. autorag/data/qa/evolve/__init__.py +0 -0
  30. autorag/data/qa/evolve/llama_index_query_evolve.py +64 -0
  31. autorag/data/qa/evolve/openai_query_evolve.py +81 -0
  32. autorag/data/qa/evolve/prompt.py +288 -0
  33. autorag/data/qa/extract_evidence.py +1 -0
  34. autorag/data/qa/filter/__init__.py +0 -0
  35. autorag/data/qa/filter/dontknow.py +117 -0
  36. autorag/data/qa/filter/passage_dependency.py +88 -0
  37. autorag/data/qa/filter/prompt.py +73 -0
  38. autorag/data/qa/generation_gt/__init__.py +0 -0
  39. autorag/data/qa/generation_gt/base.py +16 -0
  40. autorag/data/qa/generation_gt/llama_index_gen_gt.py +41 -0
  41. autorag/data/qa/generation_gt/openai_gen_gt.py +84 -0
  42. autorag/data/qa/generation_gt/prompt.py +27 -0
  43. autorag/data/qa/query/__init__.py +0 -0
  44. autorag/data/qa/query/llama_gen_query.py +82 -0
  45. autorag/data/qa/query/openai_gen_query.py +95 -0
  46. autorag/data/qa/query/prompt.py +201 -0
  47. autorag/data/qa/sample.py +26 -0
  48. autorag/data/qa/schema.py +322 -0
  49. autorag/data/utils/__init__.py +0 -0
  50. autorag/data/utils/util.py +103 -0
  51. autorag/deploy/__init__.py +9 -0
  52. autorag/deploy/api.py +303 -0
  53. autorag/deploy/base.py +235 -0
  54. autorag/deploy/gradio.py +74 -0
  55. autorag/deploy/swagger.yml +202 -0
  56. autorag/embedding/__init__.py +0 -0
  57. autorag/embedding/base.py +144 -0
  58. autorag/embedding/vllm.py +256 -0
  59. autorag/evaluation/__init__.py +3 -0
  60. autorag/evaluation/generation.py +88 -0
  61. autorag/evaluation/metric/__init__.py +22 -0
  62. autorag/evaluation/metric/deepeval_prompt.py +322 -0
  63. autorag/evaluation/metric/g_eval_prompts/coh_detailed.txt +32 -0
  64. autorag/evaluation/metric/g_eval_prompts/con_detailed.txt +33 -0
  65. autorag/evaluation/metric/g_eval_prompts/flu_detailed.txt +26 -0
  66. autorag/evaluation/metric/g_eval_prompts/rel_detailed.txt +33 -0
  67. autorag/evaluation/metric/generation.py +504 -0
  68. autorag/evaluation/metric/retrieval.py +115 -0
  69. autorag/evaluation/metric/retrieval_contents.py +65 -0
  70. autorag/evaluation/metric/util.py +88 -0
  71. autorag/evaluation/retrieval.py +83 -0
  72. autorag/evaluation/retrieval_contents.py +65 -0
  73. autorag/evaluation/util.py +43 -0
  74. autorag/evaluator.py +559 -0
  75. autorag/node_line.py +65 -0
  76. autorag/nodes/__init__.py +0 -0
  77. autorag/nodes/generator/__init__.py +4 -0
  78. autorag/nodes/generator/base.py +103 -0
  79. autorag/nodes/generator/llama_index_llm.py +169 -0
  80. autorag/nodes/generator/openai_llm.py +329 -0
  81. autorag/nodes/generator/run.py +148 -0
  82. autorag/nodes/generator/vllm.py +147 -0
  83. autorag/nodes/generator/vllm_api.py +191 -0
  84. autorag/nodes/hybridretrieval/__init__.py +2 -0
  85. autorag/nodes/hybridretrieval/base.py +58 -0
  86. autorag/nodes/hybridretrieval/hybrid_cc.py +227 -0
  87. autorag/nodes/hybridretrieval/hybrid_rrf.py +149 -0
  88. autorag/nodes/hybridretrieval/run.py +137 -0
  89. autorag/nodes/lexicalretrieval/__init__.py +1 -0
  90. autorag/nodes/lexicalretrieval/bm25.py +381 -0
  91. autorag/nodes/lexicalretrieval/run.py +148 -0
  92. autorag/nodes/passageaugmenter/__init__.py +2 -0
  93. autorag/nodes/passageaugmenter/base.py +76 -0
  94. autorag/nodes/passageaugmenter/pass_passage_augmenter.py +43 -0
  95. autorag/nodes/passageaugmenter/prev_next_augmenter.py +155 -0
  96. autorag/nodes/passageaugmenter/run.py +131 -0
  97. autorag/nodes/passagecompressor/__init__.py +4 -0
  98. autorag/nodes/passagecompressor/base.py +78 -0
  99. autorag/nodes/passagecompressor/longllmlingua.py +115 -0
  100. autorag/nodes/passagecompressor/pass_compressor.py +16 -0
  101. autorag/nodes/passagecompressor/refine.py +54 -0
  102. autorag/nodes/passagecompressor/run.py +186 -0
  103. autorag/nodes/passagecompressor/tree_summarize.py +56 -0
  104. autorag/nodes/passagefilter/__init__.py +6 -0
  105. autorag/nodes/passagefilter/base.py +40 -0
  106. autorag/nodes/passagefilter/pass_passage_filter.py +14 -0
  107. autorag/nodes/passagefilter/percentile_cutoff.py +58 -0
  108. autorag/nodes/passagefilter/recency.py +105 -0
  109. autorag/nodes/passagefilter/run.py +138 -0
  110. autorag/nodes/passagefilter/similarity_percentile_cutoff.py +134 -0
  111. autorag/nodes/passagefilter/similarity_threshold_cutoff.py +112 -0
  112. autorag/nodes/passagefilter/threshold_cutoff.py +78 -0
  113. autorag/nodes/passagereranker/__init__.py +16 -0
  114. autorag/nodes/passagereranker/base.py +44 -0
  115. autorag/nodes/passagereranker/cohere.py +118 -0
  116. autorag/nodes/passagereranker/colbert.py +213 -0
  117. autorag/nodes/passagereranker/flag_embedding.py +112 -0
  118. autorag/nodes/passagereranker/flag_embedding_llm.py +101 -0
  119. autorag/nodes/passagereranker/flashrank.py +245 -0
  120. autorag/nodes/passagereranker/jina.py +115 -0
  121. autorag/nodes/passagereranker/koreranker.py +136 -0
  122. autorag/nodes/passagereranker/mixedbreadai.py +126 -0
  123. autorag/nodes/passagereranker/monot5.py +190 -0
  124. autorag/nodes/passagereranker/openvino.py +191 -0
  125. autorag/nodes/passagereranker/pass_reranker.py +31 -0
  126. autorag/nodes/passagereranker/rankgpt.py +170 -0
  127. autorag/nodes/passagereranker/run.py +145 -0
  128. autorag/nodes/passagereranker/sentence_transformer.py +129 -0
  129. autorag/nodes/passagereranker/tart/__init__.py +1 -0
  130. autorag/nodes/passagereranker/tart/modeling_enc_t5.py +152 -0
  131. autorag/nodes/passagereranker/tart/tart.py +139 -0
  132. autorag/nodes/passagereranker/tart/tokenization_enc_t5.py +112 -0
  133. autorag/nodes/passagereranker/time_reranker.py +72 -0
  134. autorag/nodes/passagereranker/upr.py +160 -0
  135. autorag/nodes/passagereranker/voyageai.py +109 -0
  136. autorag/nodes/promptmaker/__init__.py +12 -0
  137. autorag/nodes/promptmaker/base.py +32 -0
  138. autorag/nodes/promptmaker/chat_fstring.py +73 -0
  139. autorag/nodes/promptmaker/fstring.py +49 -0
  140. autorag/nodes/promptmaker/long_context_reorder.py +83 -0
  141. autorag/nodes/promptmaker/run.py +283 -0
  142. autorag/nodes/promptmaker/window_replacement.py +85 -0
  143. autorag/nodes/queryexpansion/__init__.py +4 -0
  144. autorag/nodes/queryexpansion/base.py +62 -0
  145. autorag/nodes/queryexpansion/hyde.py +43 -0
  146. autorag/nodes/queryexpansion/multi_query_expansion.py +57 -0
  147. autorag/nodes/queryexpansion/pass_query_expansion.py +22 -0
  148. autorag/nodes/queryexpansion/query_decompose.py +111 -0
  149. autorag/nodes/queryexpansion/run.py +308 -0
  150. autorag/nodes/retrieval/__init__.py +0 -0
  151. autorag/nodes/retrieval/base.py +127 -0
  152. autorag/nodes/retrieval/run_util.py +152 -0
  153. autorag/nodes/semanticretrieval/__init__.py +1 -0
  154. autorag/nodes/semanticretrieval/run.py +148 -0
  155. autorag/nodes/semanticretrieval/vectordb.py +339 -0
  156. autorag/nodes/util.py +16 -0
  157. autorag/parser.py +37 -0
  158. autorag/schema/__init__.py +3 -0
  159. autorag/schema/base.py +35 -0
  160. autorag/schema/metricinput.py +99 -0
  161. autorag/schema/module.py +24 -0
  162. autorag/schema/node.py +144 -0
  163. autorag/strategy.py +165 -0
  164. autorag/support.py +235 -0
  165. autorag/utils/__init__.py +8 -0
  166. autorag/utils/cast.py +45 -0
  167. autorag/utils/preprocess.py +149 -0
  168. autorag/utils/util.py +759 -0
  169. autorag/validator.py +98 -0
  170. autorag/vectordb/__init__.py +75 -0
  171. autorag/vectordb/base.py +73 -0
  172. autorag/vectordb/chroma.py +118 -0
  173. autorag/vectordb/couchbase.py +239 -0
  174. autorag/vectordb/milvus.py +169 -0
  175. autorag/vectordb/pinecone.py +121 -0
  176. autorag/vectordb/qdrant.py +155 -0
  177. autorag/vectordb/weaviate.py +184 -0
  178. autorag/web.py +81 -0
  179. autorag-0.0.0.dist-info/METADATA +780 -0
  180. autorag-0.0.0.dist-info/RECORD +184 -0
  181. autorag-0.0.0.dist-info/WHEEL +5 -0
  182. autorag-0.0.0.dist-info/entry_points.txt +2 -0
  183. autorag-0.0.0.dist-info/licenses/LICENSE +201 -0
  184. 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,3 @@
1
+ from .retrieval import evaluate_retrieval
2
+ from .generation import evaluate_generation
3
+ from .retrieval_contents import evaluate_retrieval_contents
@@ -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