langroid 0.45.8__py3-none-any.whl → 0.46.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.
- langroid/embedding_models/models.py +54 -14
- langroid/language_models/openai_gpt.py +51 -2
- langroid/parsing/web_search.py +29 -16
- {langroid-0.45.8.dist-info → langroid-0.46.0.dist-info}/METADATA +1 -1
- {langroid-0.45.8.dist-info → langroid-0.46.0.dist-info}/RECORD +7 -7
- {langroid-0.45.8.dist-info → langroid-0.46.0.dist-info}/WHEEL +0 -0
- {langroid-0.45.8.dist-info → langroid-0.46.0.dist-info}/licenses/LICENSE +0 -0
@@ -10,6 +10,7 @@ from openai import AzureOpenAI, OpenAI
|
|
10
10
|
|
11
11
|
from langroid.embedding_models.base import EmbeddingModel, EmbeddingModelsConfig
|
12
12
|
from langroid.exceptions import LangroidImportError
|
13
|
+
from langroid.language_models.openai_gpt import LangDBParams
|
13
14
|
from langroid.mytypes import Embeddings
|
14
15
|
from langroid.parsing.utils import batched
|
15
16
|
|
@@ -24,6 +25,7 @@ class OpenAIEmbeddingsConfig(EmbeddingModelsConfig):
|
|
24
25
|
organization: str = ""
|
25
26
|
dims: int = 1536
|
26
27
|
context_length: int = 8192
|
28
|
+
langdb_params: LangDBParams = LangDBParams()
|
27
29
|
|
28
30
|
class Config:
|
29
31
|
# enable auto-loading of env vars with OPENAI_ prefix, e.g.
|
@@ -136,11 +138,13 @@ class EmbeddingFunctionCallable:
|
|
136
138
|
"""
|
137
139
|
embeds = []
|
138
140
|
if isinstance(self.embed_model, (OpenAIEmbeddings, AzureOpenAIEmbeddings)):
|
139
|
-
|
141
|
+
# Truncate texts to context length while preserving text format
|
142
|
+
truncated_texts = self.embed_model.truncate_texts(input)
|
140
143
|
|
141
|
-
|
144
|
+
# Process in batches
|
145
|
+
for batch in batched(truncated_texts, self.batch_size):
|
142
146
|
result = self.embed_model.client.embeddings.create(
|
143
|
-
input=batch, model=self.embed_model.config.model_name
|
147
|
+
input=batch, model=self.embed_model.config.model_name # type: ignore
|
144
148
|
)
|
145
149
|
batch_embeds = [d.embedding for d in result.data]
|
146
150
|
embeds.extend(batch_embeds)
|
@@ -183,30 +187,66 @@ class OpenAIEmbeddings(EmbeddingModel):
|
|
183
187
|
super().__init__()
|
184
188
|
self.config = config
|
185
189
|
load_dotenv()
|
186
|
-
|
190
|
+
|
191
|
+
# Check if using LangDB
|
192
|
+
self.is_langdb = self.config.model_name.startswith("langdb/")
|
193
|
+
|
194
|
+
if self.is_langdb:
|
195
|
+
self.config.model_name = self.config.model_name.replace("langdb/", "")
|
196
|
+
self.config.api_base = self.config.langdb_params.base_url
|
197
|
+
project_id = self.config.langdb_params.project_id
|
198
|
+
if project_id:
|
199
|
+
self.config.api_base += "/" + project_id + "/v1"
|
200
|
+
self.config.api_key = self.config.langdb_params.api_key
|
201
|
+
|
202
|
+
if not self.config.api_key:
|
203
|
+
self.config.api_key = os.getenv("OPENAI_API_KEY", "")
|
204
|
+
|
187
205
|
self.config.organization = os.getenv("OPENAI_ORGANIZATION", "")
|
206
|
+
|
188
207
|
if self.config.api_key == "":
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
208
|
+
if self.is_langdb:
|
209
|
+
raise ValueError(
|
210
|
+
"""
|
211
|
+
LANGDB_API_KEY must be set in .env or your environment
|
212
|
+
to use OpenAIEmbeddings via LangDB.
|
213
|
+
"""
|
214
|
+
)
|
215
|
+
else:
|
216
|
+
raise ValueError(
|
217
|
+
"""
|
218
|
+
OPENAI_API_KEY must be set in .env or your environment
|
219
|
+
to use OpenAIEmbeddings.
|
220
|
+
"""
|
221
|
+
)
|
222
|
+
|
223
|
+
self.client = OpenAI(
|
224
|
+
base_url=self.config.api_base,
|
225
|
+
api_key=self.config.api_key,
|
226
|
+
organization=self.config.organization,
|
227
|
+
)
|
228
|
+
model_for_tokenizer = self.config.model_name
|
229
|
+
if model_for_tokenizer.startswith("openai/"):
|
230
|
+
self.config.model_name = model_for_tokenizer.replace("openai/", "")
|
196
231
|
self.tokenizer = tiktoken.encoding_for_model(self.config.model_name)
|
197
232
|
|
198
|
-
def truncate_texts(self, texts: List[str]) -> List[List[int]]:
|
233
|
+
def truncate_texts(self, texts: List[str]) -> List[str] | List[List[int]]:
|
199
234
|
"""
|
200
235
|
Truncate texts to the embedding model's context length.
|
201
236
|
TODO: Maybe we should show warning, and consider doing T5 summarization?
|
202
237
|
"""
|
203
|
-
|
238
|
+
truncated_tokens = [
|
204
239
|
self.tokenizer.encode(text, disallowed_special=())[
|
205
240
|
: self.config.context_length
|
206
241
|
]
|
207
242
|
for text in texts
|
208
243
|
]
|
209
244
|
|
245
|
+
if self.is_langdb:
|
246
|
+
# LangDB embedding endpt only works with strings, not tokens
|
247
|
+
return [self.tokenizer.decode(tokens) for tokens in truncated_tokens]
|
248
|
+
return truncated_tokens
|
249
|
+
|
210
250
|
def embedding_fn(self) -> Callable[[List[str]], Embeddings]:
|
211
251
|
return EmbeddingFunctionCallable(self, self.config.batch_size)
|
212
252
|
|
@@ -256,7 +296,7 @@ class AzureOpenAIEmbeddings(EmbeddingModel):
|
|
256
296
|
)
|
257
297
|
self.tokenizer = tiktoken.encoding_for_model(self.config.model_name)
|
258
298
|
|
259
|
-
def truncate_texts(self, texts: List[str]) -> List[List[int]]:
|
299
|
+
def truncate_texts(self, texts: List[str]) -> List[str] | List[List[int]]:
|
260
300
|
"""
|
261
301
|
Truncate texts to the embedding model's context length.
|
262
302
|
TODO: Maybe we should show warning, and consider doing T5 summarization?
|
@@ -66,7 +66,7 @@ from langroid.language_models.utils import (
|
|
66
66
|
retry_with_exponential_backoff,
|
67
67
|
)
|
68
68
|
from langroid.parsing.parse_json import parse_imperfect_json
|
69
|
-
from langroid.pydantic_v1 import BaseModel
|
69
|
+
from langroid.pydantic_v1 import BaseModel, BaseSettings
|
70
70
|
from langroid.utils.configuration import settings
|
71
71
|
from langroid.utils.constants import Colors
|
72
72
|
from langroid.utils.system import friendly_error
|
@@ -82,9 +82,13 @@ DEEPSEEK_BASE_URL = "https://api.deepseek.com/v1"
|
|
82
82
|
OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1"
|
83
83
|
GEMINI_BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai"
|
84
84
|
GLHF_BASE_URL = "https://glhf.chat/api/openai/v1"
|
85
|
+
LANGDB_BASE_URL = "https://api.us-east-1.langdb.ai"
|
85
86
|
OLLAMA_API_KEY = "ollama"
|
86
87
|
DUMMY_API_KEY = "xxx"
|
87
88
|
|
89
|
+
VLLM_API_KEY = os.environ.get("VLLM_API_KEY", DUMMY_API_KEY)
|
90
|
+
LLAMACPP_API_KEY = os.environ.get("LLAMA_API_KEY", DUMMY_API_KEY)
|
91
|
+
|
88
92
|
|
89
93
|
openai_chat_model_pref_list = [
|
90
94
|
OpenAIChatModel.GPT4o,
|
@@ -177,6 +181,24 @@ def noop() -> None:
|
|
177
181
|
return None
|
178
182
|
|
179
183
|
|
184
|
+
class LangDBParams(BaseSettings):
|
185
|
+
"""
|
186
|
+
Parameters specific to LangDB integration.
|
187
|
+
"""
|
188
|
+
|
189
|
+
api_key: str = DUMMY_API_KEY
|
190
|
+
project_id: str = ""
|
191
|
+
label: Optional[str] = None
|
192
|
+
run_id: Optional[str] = None
|
193
|
+
thread_id: Optional[str] = None
|
194
|
+
base_url: str = LANGDB_BASE_URL
|
195
|
+
|
196
|
+
class Config:
|
197
|
+
# allow setting of fields via env vars,
|
198
|
+
# e.g. LANGDB_PROJECT_ID=1234
|
199
|
+
env_prefix = "LANGDB_"
|
200
|
+
|
201
|
+
|
180
202
|
class OpenAICallParams(BaseModel):
|
181
203
|
"""
|
182
204
|
Various params that can be sent to an OpenAI API chat-completion call.
|
@@ -253,6 +275,8 @@ class OpenAIGPTConfig(LLMConfig):
|
|
253
275
|
# e.g. "mistral-instruct-v0.2 (a fuzzy search is done to find the closest match)
|
254
276
|
formatter: str | None = None
|
255
277
|
hf_formatter: HFFormatter | None = None
|
278
|
+
langdb_params: LangDBParams = LangDBParams()
|
279
|
+
headers: Dict[str, str] = {}
|
256
280
|
|
257
281
|
def __init__(self, **kwargs) -> None: # type: ignore
|
258
282
|
local_model = "api_base" in kwargs and kwargs["api_base"] is not None
|
@@ -496,6 +520,7 @@ class OpenAIGPT(LanguageModel):
|
|
496
520
|
self.is_deepseek = self.is_deepseek_model()
|
497
521
|
self.is_glhf = self.config.chat_model.startswith("glhf/")
|
498
522
|
self.is_openrouter = self.config.chat_model.startswith("openrouter/")
|
523
|
+
self.is_langdb = self.config.chat_model.startswith("langdb/")
|
499
524
|
|
500
525
|
if self.is_groq:
|
501
526
|
# use groq-specific client
|
@@ -544,18 +569,39 @@ class OpenAIGPT(LanguageModel):
|
|
544
569
|
self.api_base = DEEPSEEK_BASE_URL
|
545
570
|
if self.api_key == OPENAI_API_KEY:
|
546
571
|
self.api_key = os.getenv("DEEPSEEK_API_KEY", DUMMY_API_KEY)
|
572
|
+
elif self.is_langdb:
|
573
|
+
self.config.chat_model = self.config.chat_model.replace("langdb/", "")
|
574
|
+
self.api_base = self.config.langdb_params.base_url
|
575
|
+
project_id = self.config.langdb_params.project_id
|
576
|
+
if project_id:
|
577
|
+
self.api_base += "/" + project_id + "/v1"
|
578
|
+
if self.api_key == OPENAI_API_KEY:
|
579
|
+
self.api_key = self.config.langdb_params.api_key or DUMMY_API_KEY
|
580
|
+
|
581
|
+
if self.config.langdb_params:
|
582
|
+
params = self.config.langdb_params
|
583
|
+
if params.project_id:
|
584
|
+
self.config.headers["x-project-id"] = params.project_id
|
585
|
+
if params.label:
|
586
|
+
self.config.headers["x-label"] = params.label
|
587
|
+
if params.run_id:
|
588
|
+
self.config.headers["x-run-id"] = params.run_id
|
589
|
+
if params.thread_id:
|
590
|
+
self.config.headers["x-thread-id"] = params.thread_id
|
547
591
|
|
548
592
|
self.client = OpenAI(
|
549
593
|
api_key=self.api_key,
|
550
594
|
base_url=self.api_base,
|
551
595
|
organization=self.config.organization,
|
552
596
|
timeout=Timeout(self.config.timeout),
|
597
|
+
default_headers=self.config.headers,
|
553
598
|
)
|
554
599
|
self.async_client = AsyncOpenAI(
|
555
600
|
api_key=self.api_key,
|
556
601
|
organization=self.config.organization,
|
557
602
|
base_url=self.api_base,
|
558
603
|
timeout=Timeout(self.config.timeout),
|
604
|
+
default_headers=self.config.headers,
|
559
605
|
)
|
560
606
|
|
561
607
|
self.cache: CacheDB | None = None
|
@@ -1028,6 +1074,7 @@ class OpenAIGPT(LanguageModel):
|
|
1028
1074
|
OpenAIResponse object (with choices, usage)
|
1029
1075
|
|
1030
1076
|
"""
|
1077
|
+
|
1031
1078
|
completion = ""
|
1032
1079
|
reasoning = ""
|
1033
1080
|
function_args = ""
|
@@ -1075,7 +1122,9 @@ class OpenAIGPT(LanguageModel):
|
|
1075
1122
|
)
|
1076
1123
|
|
1077
1124
|
@staticmethod
|
1078
|
-
def tool_deltas_to_tools(
|
1125
|
+
def tool_deltas_to_tools(
|
1126
|
+
tools: List[Dict[str, Any]],
|
1127
|
+
) -> Tuple[
|
1079
1128
|
str,
|
1080
1129
|
List[OpenAIToolCall],
|
1081
1130
|
List[Dict[str, Any]],
|
langroid/parsing/web_search.py
CHANGED
@@ -28,7 +28,7 @@ class WebSearchResult:
|
|
28
28
|
def __init__(
|
29
29
|
self,
|
30
30
|
title: str,
|
31
|
-
link: str,
|
31
|
+
link: str | None,
|
32
32
|
max_content_length: int = 3500,
|
33
33
|
max_summary_length: int = 300,
|
34
34
|
):
|
@@ -50,6 +50,8 @@ class WebSearchResult:
|
|
50
50
|
return self.full_content[: self.max_summary_length]
|
51
51
|
|
52
52
|
def get_full_content(self) -> str:
|
53
|
+
if self.link is None:
|
54
|
+
return "Error: No Search Result"
|
53
55
|
try:
|
54
56
|
# First check headers only to get content length and type
|
55
57
|
head_response: Response = requests.head(self.link, timeout=5)
|
@@ -83,7 +85,7 @@ class WebSearchResult:
|
|
83
85
|
def to_dict(self) -> Dict[str, str]:
|
84
86
|
return {
|
85
87
|
"title": self.title,
|
86
|
-
"link": self.link,
|
88
|
+
"link": self.link or "",
|
87
89
|
"summary": self.summary,
|
88
90
|
"full_content": self.full_content,
|
89
91
|
}
|
@@ -175,21 +177,32 @@ def exa_search(query: str, num_results: int = 5) -> List[WebSearchResult]:
|
|
175
177
|
|
176
178
|
client = Exa(api_key=api_key)
|
177
179
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
raw_results = response.results
|
183
|
-
|
184
|
-
return [
|
185
|
-
WebSearchResult(
|
186
|
-
title=result.title or "",
|
187
|
-
link=result.url,
|
188
|
-
max_content_length=3500,
|
189
|
-
max_summary_length=300,
|
180
|
+
try:
|
181
|
+
response = client.search(
|
182
|
+
query=query,
|
183
|
+
num_results=num_results,
|
190
184
|
)
|
191
|
-
|
192
|
-
|
185
|
+
raw_results = response.results
|
186
|
+
|
187
|
+
return [
|
188
|
+
WebSearchResult(
|
189
|
+
title=result.title or "",
|
190
|
+
link=result.url,
|
191
|
+
max_content_length=3500,
|
192
|
+
max_summary_length=300,
|
193
|
+
)
|
194
|
+
for result in raw_results
|
195
|
+
if result.url is not None
|
196
|
+
]
|
197
|
+
except Exception:
|
198
|
+
return [
|
199
|
+
WebSearchResult(
|
200
|
+
title="Error",
|
201
|
+
link=None,
|
202
|
+
max_content_length=3500,
|
203
|
+
max_summary_length=300,
|
204
|
+
)
|
205
|
+
]
|
193
206
|
|
194
207
|
|
195
208
|
def duckduckgo_search(query: str, num_results: int = 5) -> List[WebSearchResult]:
|
@@ -59,7 +59,7 @@ langroid/cachedb/momento_cachedb.py,sha256=YEOJ62hEcV6iIeMr5aGgRYgWQqFYaej9gEDEc
|
|
59
59
|
langroid/cachedb/redis_cachedb.py,sha256=7kgnbf4b5CKsCrlL97mHWKvdvlLt8zgn7lc528jEpiE,5141
|
60
60
|
langroid/embedding_models/__init__.py,sha256=KyYxR3jDFUCfYjSuCL86qjAmrq6mXXjOT4lFNOKVj6Y,955
|
61
61
|
langroid/embedding_models/base.py,sha256=Ml7oA6PzQm0wZmIYn3fhF7dvZCi-amviWUwOeBegH3A,2562
|
62
|
-
langroid/embedding_models/models.py,sha256=
|
62
|
+
langroid/embedding_models/models.py,sha256=iGRrQR7ehDunA_7cPMu3CiHFugYWDkauOsiqHH-bv9s,20725
|
63
63
|
langroid/embedding_models/remote_embeds.py,sha256=6_kjXByVbqhY9cGwl9R83ZcYC2km-nGieNNAo1McHaY,5151
|
64
64
|
langroid/embedding_models/protoc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
65
65
|
langroid/embedding_models/protoc/embeddings.proto,sha256=_O-SgFpTaylQeOTgSpxhEJ7CUw7PeCQQJLaPqpPYKJg,321
|
@@ -72,7 +72,7 @@ langroid/language_models/base.py,sha256=mDYmFCBCLdq8_Uvws4MiewwEgcOCP8Qb0e5yUXr3
|
|
72
72
|
langroid/language_models/config.py,sha256=9Q8wk5a7RQr8LGMT_0WkpjY8S4ywK06SalVRjXlfCiI,378
|
73
73
|
langroid/language_models/mock_lm.py,sha256=5BgHKDVRWFbUwDT_PFgTZXz9-k8wJSA2e3PZmyDgQ1k,4022
|
74
74
|
langroid/language_models/model_info.py,sha256=tfBBxL0iUf2mVN6CjcvqflzFUVg2oZqOJZexZ8jHTYA,12216
|
75
|
-
langroid/language_models/openai_gpt.py,sha256=
|
75
|
+
langroid/language_models/openai_gpt.py,sha256=Re4T1my9rhOPI-w4JCluhAZUVUIbW2AZJ3MIJMYjRuk,79633
|
76
76
|
langroid/language_models/utils.py,sha256=L4_CbihDMTGcsg0TOG1Yd5JFEto46--h7CX_14m89sQ,5016
|
77
77
|
langroid/language_models/prompt_formatter/__init__.py,sha256=2-5cdE24XoFDhifOLl8yiscohil1ogbP1ECkYdBlBsk,372
|
78
78
|
langroid/language_models/prompt_formatter/base.py,sha256=eDS1sgRNZVnoajwV_ZIha6cba5Dt8xjgzdRbPITwx3Q,1221
|
@@ -94,7 +94,7 @@ langroid/parsing/table_loader.py,sha256=qNM4obT_0Y4tjrxNBCNUYjKQ9oETCZ7FbolKBTcz
|
|
94
94
|
langroid/parsing/url_loader.py,sha256=obi_kj6ehBkdh5mXNtYCXpm3KCuExoy2D1ODVlFbXbQ,4895
|
95
95
|
langroid/parsing/urls.py,sha256=Tjzr64YsCusiYkY0LEGB5-rSuX8T2P_4DVoOFKAeKuI,8081
|
96
96
|
langroid/parsing/utils.py,sha256=WwqzOhbQRlorbVvddDIZKv9b1KqZCBDm955lgIHDXRw,12828
|
97
|
-
langroid/parsing/web_search.py,sha256=
|
97
|
+
langroid/parsing/web_search.py,sha256=sARV1Tku4wiInhuCz0kRaMHcoF6Ok6CLu7vapLS8hjs,8222
|
98
98
|
langroid/prompts/__init__.py,sha256=RW11vK6jiLPuaUh4GpeFvstti73gkm8_rDMtrbo2YsU,142
|
99
99
|
langroid/prompts/dialog.py,sha256=SpfiSyofSgy2pwD1YboHR_yHO3LEEMbv6j2sm874jKo,331
|
100
100
|
langroid/prompts/prompts_config.py,sha256=p_lp9nbMuQwhhMwAZsOxveRw9C0ZFZvql7pdIfgVZYo,143
|
@@ -127,7 +127,7 @@ langroid/vector_store/pineconedb.py,sha256=otxXZNaBKb9f_H75HTaU3lMHiaR2NUp5MqwLZ
|
|
127
127
|
langroid/vector_store/postgres.py,sha256=wHPtIi2qM4fhO4pMQr95pz1ZCe7dTb2hxl4VYspGZoA,16104
|
128
128
|
langroid/vector_store/qdrantdb.py,sha256=O6dSBoDZ0jzfeVBd7LLvsXu083xs2fxXtPa9gGX3JX4,18443
|
129
129
|
langroid/vector_store/weaviatedb.py,sha256=Yn8pg139gOy3zkaPfoTbMXEEBCiLiYa1MU5d_3UA1K4,11847
|
130
|
-
langroid-0.
|
131
|
-
langroid-0.
|
132
|
-
langroid-0.
|
133
|
-
langroid-0.
|
130
|
+
langroid-0.46.0.dist-info/METADATA,sha256=S5uBIAjkQEV4KbQSZ2OH-YMoMfGIJtnulBdaYNouSpw,63389
|
131
|
+
langroid-0.46.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
132
|
+
langroid-0.46.0.dist-info/licenses/LICENSE,sha256=EgVbvA6VSYgUlvC3RvPKehSg7MFaxWDsFuzLOsPPfJg,1065
|
133
|
+
langroid-0.46.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|