mb-rag 1.1.56.post0__py3-none-any.whl → 1.1.58__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.
Potentially problematic release.
This version of mb-rag might be problematic. Click here for more details.
- mb_rag/basic.py +375 -306
- mb_rag/chatbot/chains.py +206 -206
- mb_rag/chatbot/conversation.py +185 -185
- mb_rag/chatbot/prompts.py +58 -58
- mb_rag/rag/embeddings.py +810 -810
- mb_rag/utils/all_data_extract.py +64 -64
- mb_rag/utils/bounding_box.py +231 -231
- mb_rag/utils/document_extract.py +354 -354
- mb_rag/utils/extra.py +73 -73
- mb_rag/utils/pdf_extract.py +428 -428
- mb_rag/version.py +1 -1
- {mb_rag-1.1.56.post0.dist-info → mb_rag-1.1.58.dist-info}/METADATA +11 -11
- mb_rag-1.1.58.dist-info/RECORD +19 -0
- mb_rag-1.1.56.post0.dist-info/RECORD +0 -19
- {mb_rag-1.1.56.post0.dist-info → mb_rag-1.1.58.dist-info}/WHEEL +0 -0
- {mb_rag-1.1.56.post0.dist-info → mb_rag-1.1.58.dist-info}/top_level.txt +0 -0
mb_rag/basic.py
CHANGED
|
@@ -1,306 +1,375 @@
|
|
|
1
|
-
## file for loading all models for chat/rag
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
from langchain_core.messages import HumanMessage
|
|
5
|
-
from mb_rag.utils.extra import check_package
|
|
6
|
-
import base64
|
|
7
|
-
from .utils.extra import check_package
|
|
8
|
-
from typing import Any
|
|
9
|
-
from .utils.all_data_extract import DocumentExtractor
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
Args:
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
print("
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
1
|
+
## file for loading all models for chat/rag
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from langchain_core.messages import HumanMessage
|
|
5
|
+
from mb_rag.utils.extra import check_package
|
|
6
|
+
import base64
|
|
7
|
+
from .utils.extra import check_package
|
|
8
|
+
from typing import Any
|
|
9
|
+
from .utils.all_data_extract import DocumentExtractor
|
|
10
|
+
import pandas as pd
|
|
11
|
+
from tqdm.auto import tqdm
|
|
12
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
'ModelFactory',
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
class ModelFactory:
|
|
19
|
+
"""Factory class for creating different types of chatbot models"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, model_type: str = 'openai', model_name: str = "gpt-4o", **kwargs) -> Any:
|
|
22
|
+
"""
|
|
23
|
+
Factory method to create any type of model
|
|
24
|
+
Args:
|
|
25
|
+
model_type (str): Type of model to create. Default is OpenAI. Options are openai, anthropic, google, ollama , groq
|
|
26
|
+
model_name (str): Name of the model
|
|
27
|
+
**kwargs: Additional arguments
|
|
28
|
+
Returns:
|
|
29
|
+
Any: Chatbot model
|
|
30
|
+
"""
|
|
31
|
+
creators = {
|
|
32
|
+
'openai': self.create_openai,
|
|
33
|
+
'anthropic': self.create_anthropic,
|
|
34
|
+
'google': self.create_google,
|
|
35
|
+
'ollama': self.create_ollama,
|
|
36
|
+
'groq': self.create_groq,
|
|
37
|
+
'deepseek': self.create_deepseek,
|
|
38
|
+
'qwen' : self.create_qwen,
|
|
39
|
+
'hugging_face': self.create_hugging_face
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
self.model_type = model_type
|
|
43
|
+
self.model_name = model_name
|
|
44
|
+
model_data = creators.get(model_type)
|
|
45
|
+
if not model_data:
|
|
46
|
+
raise ValueError(f"Unsupported model type: {model_type}")
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
self.model = model_data(model_name, **kwargs)
|
|
50
|
+
except Exception as e:
|
|
51
|
+
raise ValueError(f"Error creating {model_type} model: {str(e)}")
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def create_openai(cls, model_name: str = "gpt-4o", **kwargs) -> Any:
|
|
55
|
+
"""
|
|
56
|
+
Create OpenAI chatbot model
|
|
57
|
+
Args:
|
|
58
|
+
model_name (str): Name of the model
|
|
59
|
+
**kwargs: Additional arguments
|
|
60
|
+
Returns:
|
|
61
|
+
ChatOpenAI: Chatbot model
|
|
62
|
+
"""
|
|
63
|
+
if not check_package("openai"):
|
|
64
|
+
raise ImportError("OpenAI package not found. Please install it using: pip install openai langchain-openai")
|
|
65
|
+
|
|
66
|
+
from langchain_openai import ChatOpenAI
|
|
67
|
+
kwargs["model_name"] = model_name
|
|
68
|
+
return ChatOpenAI(**kwargs)
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def create_anthropic(cls, model_name: str = "claude-3-opus-20240229", **kwargs) -> Any:
|
|
72
|
+
"""
|
|
73
|
+
Create Anthropic chatbot model
|
|
74
|
+
Args:
|
|
75
|
+
model_name (str): Name of the model
|
|
76
|
+
**kwargs: Additional arguments
|
|
77
|
+
Returns:
|
|
78
|
+
ChatAnthropic: Chatbot model
|
|
79
|
+
"""
|
|
80
|
+
if not check_package("anthropic"):
|
|
81
|
+
raise ImportError("Anthropic package not found. Please install it using: pip install anthropic langchain-anthropic")
|
|
82
|
+
|
|
83
|
+
from langchain_anthropic import ChatAnthropic
|
|
84
|
+
kwargs["model_name"] = model_name
|
|
85
|
+
return ChatAnthropic(**kwargs)
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
def create_google(cls, model_name: str = "gemini-2.0-flash", **kwargs) -> Any:
|
|
89
|
+
"""
|
|
90
|
+
Create Google chatbot model
|
|
91
|
+
Args:
|
|
92
|
+
model_name (str): Name of the model
|
|
93
|
+
**kwargs: Additional arguments
|
|
94
|
+
Returns:
|
|
95
|
+
ChatGoogleGenerativeAI: Chatbot model
|
|
96
|
+
"""
|
|
97
|
+
if not check_package("langchain_google_genai"):
|
|
98
|
+
raise ImportError("langchain_google_genai package not found. Please install it using: pip install google-generativeai")
|
|
99
|
+
|
|
100
|
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
|
101
|
+
kwargs["model"] = model_name
|
|
102
|
+
return ChatGoogleGenerativeAI(**kwargs)
|
|
103
|
+
|
|
104
|
+
@classmethod
|
|
105
|
+
def create_ollama(cls, model_name: str = "llama3", **kwargs) -> Any:
|
|
106
|
+
"""
|
|
107
|
+
Create Ollama chatbot model
|
|
108
|
+
Args:
|
|
109
|
+
model_name (str): Name of the model
|
|
110
|
+
**kwargs: Additional arguments
|
|
111
|
+
Returns:
|
|
112
|
+
Ollama: Chatbot model
|
|
113
|
+
"""
|
|
114
|
+
if not check_package("langchain_ollama"):
|
|
115
|
+
raise ImportError("Langchain Community package not found. Please install it using: pip install langchain_ollama")
|
|
116
|
+
|
|
117
|
+
from langchain_ollama import ChatOllama
|
|
118
|
+
|
|
119
|
+
print(f"Current Ollama serve model is {os.system('ollama ps')}")
|
|
120
|
+
kwargs["model"] = model_name
|
|
121
|
+
return ChatOllama(**kwargs)
|
|
122
|
+
|
|
123
|
+
@classmethod
|
|
124
|
+
def create_groq(cls, model_name: str = "llama-3.3-70b-versatile", **kwargs) -> Any:
|
|
125
|
+
"""
|
|
126
|
+
Create Groq chatbot model
|
|
127
|
+
Args:
|
|
128
|
+
model_name (str): Name of the model
|
|
129
|
+
**kwargs: Additional arguments. Options are: temperature, groq_api_key, model_name
|
|
130
|
+
Returns:
|
|
131
|
+
ChatGroq: Chatbot model
|
|
132
|
+
"""
|
|
133
|
+
if not check_package("langchain_groq"):
|
|
134
|
+
raise ImportError("Langchain Groq package not found. Please install it using: pip install langchain-groq")
|
|
135
|
+
|
|
136
|
+
from langchain_groq import ChatGroq
|
|
137
|
+
kwargs["model"] = model_name
|
|
138
|
+
return ChatGroq(**kwargs)
|
|
139
|
+
|
|
140
|
+
@classmethod
|
|
141
|
+
def create_deepseek(cls, model_name: str = "deepseek-chat", **kwargs) -> Any:
|
|
142
|
+
"""
|
|
143
|
+
Create Deepseek chatbot model
|
|
144
|
+
Args:
|
|
145
|
+
model_name (str): Name of the model
|
|
146
|
+
**kwargs: Additional arguments
|
|
147
|
+
Returns:
|
|
148
|
+
ChatDeepseek: Chatbot model
|
|
149
|
+
"""
|
|
150
|
+
if not check_package("langchain_deepseek"):
|
|
151
|
+
raise ImportError("Langchain Deepseek package not found. Please install it using: pip install langchain-deepseek")
|
|
152
|
+
|
|
153
|
+
from langchain_deepseek import ChatDeepSeek
|
|
154
|
+
kwargs["model"] = model_name
|
|
155
|
+
return ChatDeepSeek(**kwargs)
|
|
156
|
+
|
|
157
|
+
@classmethod
|
|
158
|
+
def create_qwen(cls, model_name: str = "qwen", **kwargs) -> Any:
|
|
159
|
+
"""
|
|
160
|
+
Create Qwen chatbot model
|
|
161
|
+
Args:
|
|
162
|
+
model_name (str): Name of the model
|
|
163
|
+
**kwargs: Additional arguments
|
|
164
|
+
Returns:
|
|
165
|
+
ChatQwen: Chatbot model
|
|
166
|
+
"""
|
|
167
|
+
if not check_package("langchain_community"):
|
|
168
|
+
raise ImportError("Langchain Qwen package not found. Please install it using: pip install langchain_community")
|
|
169
|
+
|
|
170
|
+
from langchain_community.chat_models.tongyi import ChatTongyi
|
|
171
|
+
kwargs["model"] = model_name
|
|
172
|
+
return ChatTongyi(streaming=True,**kwargs)
|
|
173
|
+
|
|
174
|
+
@classmethod
|
|
175
|
+
def create_hugging_face(cls, model_name: str = "Qwen/Qwen2.5-VL-7B-Instruct",model_function: str = "image-text-to-text",
|
|
176
|
+
device='cpu',**kwargs) -> Any:
|
|
177
|
+
"""
|
|
178
|
+
Create and load hugging face model.
|
|
179
|
+
Args:
|
|
180
|
+
model_name (str): Name of the model
|
|
181
|
+
model_function (str): model function. Default is image-text-to-text.
|
|
182
|
+
device (str): Device to use. Default is cpu
|
|
183
|
+
**kwargs: Additional arguments
|
|
184
|
+
Returns:
|
|
185
|
+
ChatHuggingFace: Chatbot model
|
|
186
|
+
"""
|
|
187
|
+
if not check_package("transformers"):
|
|
188
|
+
raise ImportError("Transformers package not found. Please install it using: pip install transformers")
|
|
189
|
+
if not check_package("langchain_huggingface"):
|
|
190
|
+
raise ImportError("langchain_huggingface package not found. Please install it using: pip install langchain_huggingface")
|
|
191
|
+
if not check_package("torch"):
|
|
192
|
+
raise ImportError("Torch package not found. Please install it using: pip install torch")
|
|
193
|
+
|
|
194
|
+
from langchain_huggingface import HuggingFacePipeline
|
|
195
|
+
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline, AutoModelForImageTextToText,AutoProcessor
|
|
196
|
+
import torch
|
|
197
|
+
|
|
198
|
+
device = torch.device(device) if torch.cuda.is_available() else torch.device("cpu")
|
|
199
|
+
|
|
200
|
+
temperature = kwargs.pop("temperature", 0.7)
|
|
201
|
+
max_length = kwargs.pop("max_length", 1024)
|
|
202
|
+
|
|
203
|
+
if model_function == "image-text-to-text":
|
|
204
|
+
tokenizer = AutoProcessor.from_pretrained(model_name,trust_remote_code=True)
|
|
205
|
+
model = AutoModelForImageTextToText.from_pretrained(
|
|
206
|
+
model_name,
|
|
207
|
+
torch_dtype=torch.float16 if device == "cuda" else torch.float32,
|
|
208
|
+
device_map=device,
|
|
209
|
+
trust_remote_code=True,
|
|
210
|
+
**kwargs
|
|
211
|
+
)
|
|
212
|
+
else:
|
|
213
|
+
tokenizer = AutoTokenizer.from_pretrained(model_name,trust_remote_code=True)
|
|
214
|
+
model = AutoModelForCausalLM.from_pretrained(
|
|
215
|
+
model_name,
|
|
216
|
+
torch_dtype=torch.float16 if device == "cuda" else torch.float32,
|
|
217
|
+
device_map=device,
|
|
218
|
+
trust_remote_code=True,
|
|
219
|
+
**kwargs)
|
|
220
|
+
|
|
221
|
+
# Create pipeline
|
|
222
|
+
pipe = pipeline(
|
|
223
|
+
model_function,
|
|
224
|
+
model=model,
|
|
225
|
+
tokenizer=tokenizer,
|
|
226
|
+
max_length=max_length,
|
|
227
|
+
temperature=temperature
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# Create and return LangChain HuggingFacePipeline
|
|
231
|
+
return HuggingFacePipeline(pipeline=pipe)
|
|
232
|
+
|
|
233
|
+
def _reset_model(self):
|
|
234
|
+
"""Reset the model"""
|
|
235
|
+
self.model = self.model.reset()
|
|
236
|
+
|
|
237
|
+
def invoke_query(self,query: str,file_path: str = None,get_content_only: bool = True,images: list = None,pydantic_model = None) -> str:
|
|
238
|
+
"""
|
|
239
|
+
Invoke the model
|
|
240
|
+
Args:
|
|
241
|
+
query (str): Query to send to the model
|
|
242
|
+
file_path (str): Path to text file to load. Default is None
|
|
243
|
+
get_content_only (bool): Whether to return only content
|
|
244
|
+
images (list): List of images to send to the model
|
|
245
|
+
pydantic_model: Pydantic model for structured output
|
|
246
|
+
Returns:
|
|
247
|
+
str: Response from the model
|
|
248
|
+
"""
|
|
249
|
+
if file_path:
|
|
250
|
+
loader = DocumentExtractor()
|
|
251
|
+
data = loader.get_data(file_path)
|
|
252
|
+
query = query + "\n\n" + data
|
|
253
|
+
|
|
254
|
+
structured_model = None
|
|
255
|
+
if pydantic_model is not None:
|
|
256
|
+
try:
|
|
257
|
+
structured_model = self.model.with_structured_output(pydantic_model)
|
|
258
|
+
except Exception as e:
|
|
259
|
+
raise ValueError(f"Error with pydantic_model: {e}")
|
|
260
|
+
if structured_model is None:
|
|
261
|
+
structured_model = self.model
|
|
262
|
+
else:
|
|
263
|
+
print("Using structured model with pydantic schema. So get_content_only is set to False.")
|
|
264
|
+
get_content_only = False # Override to get full response when using structured model
|
|
265
|
+
if images:
|
|
266
|
+
message = self._model_invoke_images(
|
|
267
|
+
images=images,
|
|
268
|
+
prompt=query)
|
|
269
|
+
res = structured_model.invoke([message])
|
|
270
|
+
else:
|
|
271
|
+
res = structured_model.invoke(query)
|
|
272
|
+
if get_content_only:
|
|
273
|
+
try:
|
|
274
|
+
return res.content
|
|
275
|
+
except Exception:
|
|
276
|
+
return res
|
|
277
|
+
return res
|
|
278
|
+
|
|
279
|
+
def invoke_query_threads(self,query_list: list,get_content_only: bool = True,input_data: list = None,n_workers: int = 4,pydantic_model=None) -> pd.DataFrame:
|
|
280
|
+
"""
|
|
281
|
+
Invoke the model with multiple threads (parallel queries).
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
query_list (list): List of queries to send to the model
|
|
285
|
+
get_content_only (bool): Whether to return only content
|
|
286
|
+
input_data (list): List of input data for the model
|
|
287
|
+
n_workers (int): Number of workers to use for threading
|
|
288
|
+
pydantic_model: Pydantic model for structured output
|
|
289
|
+
|
|
290
|
+
Returns:
|
|
291
|
+
pandas.DataFrame: Response from the model
|
|
292
|
+
"""
|
|
293
|
+
if not isinstance(query_list, list):
|
|
294
|
+
raise ValueError("query_list must be a list of strings")
|
|
295
|
+
if input_data is not None and not isinstance(input_data, list):
|
|
296
|
+
raise ValueError("input_data should be a list of messages")
|
|
297
|
+
if input_data is not None and len(input_data) != len(query_list):
|
|
298
|
+
raise ValueError("Length of input_data should equal length of query_list")
|
|
299
|
+
|
|
300
|
+
print("Length of query_list:", len(query_list))
|
|
301
|
+
|
|
302
|
+
df = pd.DataFrame(query_list, columns=["query"])
|
|
303
|
+
df["response"] = None
|
|
304
|
+
|
|
305
|
+
structured_model = None
|
|
306
|
+
if pydantic_model is not None:
|
|
307
|
+
try:
|
|
308
|
+
structured_model = self.model.with_structured_output(pydantic_model)
|
|
309
|
+
print("Using structured model with Pydantic schema. Setting get_content_only=False.")
|
|
310
|
+
get_content_only = False
|
|
311
|
+
except Exception as e:
|
|
312
|
+
raise ValueError(f"Error initializing pydantic_model: {e}")
|
|
313
|
+
else:
|
|
314
|
+
structured_model = self.model
|
|
315
|
+
|
|
316
|
+
def process_one(i, query_data):
|
|
317
|
+
try:
|
|
318
|
+
if input_data is not None and len(input_data) > 0:
|
|
319
|
+
image_data = input_data[i]
|
|
320
|
+
message = self._model_invoke_images(images=image_data, prompt=query_data)
|
|
321
|
+
res = structured_model.invoke([message])
|
|
322
|
+
else:
|
|
323
|
+
res = structured_model.invoke(query_data)
|
|
324
|
+
|
|
325
|
+
if get_content_only:
|
|
326
|
+
try:
|
|
327
|
+
res = res.content
|
|
328
|
+
except Exception:
|
|
329
|
+
pass
|
|
330
|
+
return i, query_data, res
|
|
331
|
+
except Exception as e:
|
|
332
|
+
return i, query_data, f"Error: {e}"
|
|
333
|
+
|
|
334
|
+
# Run all queries concurrently
|
|
335
|
+
with ThreadPoolExecutor(max_workers=n_workers) as executor:
|
|
336
|
+
futures = [executor.submit(process_one, i, q) for i, q in enumerate(query_list)]
|
|
337
|
+
for future in tqdm(as_completed(futures), total=len(futures), desc="Processing queries"):
|
|
338
|
+
i, query_data, res = future.result()
|
|
339
|
+
df.at[i, "query"] = query_data
|
|
340
|
+
df.at[i, "response"] = res
|
|
341
|
+
|
|
342
|
+
df.sort_index(inplace=True)
|
|
343
|
+
return df
|
|
344
|
+
|
|
345
|
+
def _image_to_base64(self,image):
|
|
346
|
+
with open(image, "rb") as f:
|
|
347
|
+
return base64.b64encode(f.read()).decode('utf-8')
|
|
348
|
+
|
|
349
|
+
def _model_invoke_images(self, images: list, prompt: str) -> str:
|
|
350
|
+
"""
|
|
351
|
+
Function to invoke the model with images
|
|
352
|
+
Args:
|
|
353
|
+
images (list): List of images
|
|
354
|
+
prompt (str): Prompt
|
|
355
|
+
Returns:
|
|
356
|
+
str: Output from the model
|
|
357
|
+
"""
|
|
358
|
+
base64_images = [self._image_to_base64(image) for image in images]
|
|
359
|
+
image_prompt_create = [{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_images[i]}"}} for i in range(len(images))]
|
|
360
|
+
prompt_new = [{"type": "text", "text": prompt}, *image_prompt_create]
|
|
361
|
+
|
|
362
|
+
message = HumanMessage(content=prompt_new)
|
|
363
|
+
return message
|
|
364
|
+
|
|
365
|
+
def _get_llm_metadata(self):
|
|
366
|
+
"""
|
|
367
|
+
Returns Basic metadata about the LLM
|
|
368
|
+
"""
|
|
369
|
+
print("Model Name: ", self.model)
|
|
370
|
+
print("Model Temperature: ", self.model.temperature)
|
|
371
|
+
print("Model Max Tokens: ", self.model.max_output_tokens)
|
|
372
|
+
print("Model Top P: ", self.model.top_p)
|
|
373
|
+
print("Model Top K: ", self.model.top_k)
|
|
374
|
+
print("Model Input Schema:",self.model.input_schema)
|
|
375
|
+
|