tavily-python 0.7.18__tar.gz → 0.7.20__tar.gz
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.
- {tavily_python-0.7.18 → tavily_python-0.7.20}/PKG-INFO +1 -1
- {tavily_python-0.7.18 → tavily_python-0.7.20}/setup.py +1 -1
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tavily/async_tavily.py +4 -4
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tavily/tavily.py +72 -124
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tavily_python.egg-info/PKG-INFO +1 -1
- {tavily_python-0.7.18 → tavily_python-0.7.20}/LICENSE +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/README.md +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/setup.cfg +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tavily/__init__.py +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tavily/config.py +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tavily/errors.py +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tavily/hybrid_rag/__init__.py +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tavily/hybrid_rag/hybrid_rag.py +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tavily/utils.py +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tavily_python.egg-info/SOURCES.txt +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tavily_python.egg-info/dependency_links.txt +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tavily_python.egg-info/requires.txt +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tavily_python.egg-info/top_level.txt +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tests/test_crawl.py +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tests/test_errors.py +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tests/test_map.py +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tests/test_research.py +0 -0
- {tavily_python-0.7.18 → tavily_python-0.7.20}/tests/test_search.py +0 -0
|
@@ -157,7 +157,7 @@ class AsyncTavilyClient:
|
|
|
157
157
|
**kwargs, # Accept custom arguments
|
|
158
158
|
) -> dict:
|
|
159
159
|
"""
|
|
160
|
-
Combined search method. Set search_depth to either "basic" or "
|
|
160
|
+
Combined search method. Set search_depth to either "basic", "advanced", "fast", or "ultra-fast".
|
|
161
161
|
"""
|
|
162
162
|
timeout = min(timeout, 120)
|
|
163
163
|
response_dict = await self._search(query,
|
|
@@ -508,7 +508,7 @@ class AsyncTavilyClient:
|
|
|
508
508
|
|
|
509
509
|
async def get_search_context(self,
|
|
510
510
|
query: str,
|
|
511
|
-
search_depth: Literal["basic", "advanced"] = "basic",
|
|
511
|
+
search_depth: Literal["basic", "advanced", "fast", "ultra-fast"] = "basic",
|
|
512
512
|
topic: Literal["general", "news", "finance"] = "general",
|
|
513
513
|
days: int = 7,
|
|
514
514
|
max_results: int = 5,
|
|
@@ -550,7 +550,7 @@ class AsyncTavilyClient:
|
|
|
550
550
|
|
|
551
551
|
async def qna_search(self,
|
|
552
552
|
query: str,
|
|
553
|
-
search_depth: Literal["basic", "advanced"] = "advanced",
|
|
553
|
+
search_depth: Literal["basic", "advanced", "fast", "ultra-fast"] = "advanced",
|
|
554
554
|
topic: Literal["general", "news", "finance"] = "general",
|
|
555
555
|
days: int = 7,
|
|
556
556
|
max_results: int = 5,
|
|
@@ -584,7 +584,7 @@ class AsyncTavilyClient:
|
|
|
584
584
|
|
|
585
585
|
async def get_company_info(self,
|
|
586
586
|
query: str,
|
|
587
|
-
search_depth: Literal["basic", "advanced"] = "advanced",
|
|
587
|
+
search_depth: Literal["basic", "advanced", "fast", "ultra-fast"] = "advanced",
|
|
588
588
|
max_results: int = 5,
|
|
589
589
|
timeout: float = 60,
|
|
590
590
|
country: str = None,
|
|
@@ -3,7 +3,6 @@ import json
|
|
|
3
3
|
import os
|
|
4
4
|
import warnings
|
|
5
5
|
from typing import Literal, Sequence, Optional, List, Union, Generator
|
|
6
|
-
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
7
6
|
from .utils import get_max_items_from_list
|
|
8
7
|
from .errors import UsageLimitExceededError, InvalidAPIKeyError, MissingAPIKeyError, BadRequestError, ForbiddenError, TimeoutError
|
|
9
8
|
|
|
@@ -38,6 +37,21 @@ class TavilyClient:
|
|
|
38
37
|
**({"X-Project-ID": tavily_project} if tavily_project else {})
|
|
39
38
|
}
|
|
40
39
|
|
|
40
|
+
self.session = requests.Session()
|
|
41
|
+
self.session.headers.update(self.headers)
|
|
42
|
+
if self.proxies:
|
|
43
|
+
self.session.proxies.update(self.proxies)
|
|
44
|
+
|
|
45
|
+
def close(self):
|
|
46
|
+
"""Close the session and release resources."""
|
|
47
|
+
self.session.close()
|
|
48
|
+
|
|
49
|
+
def __enter__(self):
|
|
50
|
+
return self
|
|
51
|
+
|
|
52
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
53
|
+
self.close()
|
|
54
|
+
|
|
41
55
|
def _search(self,
|
|
42
56
|
query: str,
|
|
43
57
|
search_depth: Literal["basic", "advanced", "fast", "ultra-fast"] = None,
|
|
@@ -89,9 +103,11 @@ class TavilyClient:
|
|
|
89
103
|
data.update(kwargs)
|
|
90
104
|
|
|
91
105
|
timeout = min(timeout, 120)
|
|
106
|
+
url = self.base_url + "/search"
|
|
107
|
+
payload = json.dumps(data)
|
|
92
108
|
|
|
93
109
|
try:
|
|
94
|
-
response =
|
|
110
|
+
response = self.session.post(url, data=payload, timeout=timeout)
|
|
95
111
|
except requests.exceptions.Timeout:
|
|
96
112
|
raise TimeoutError(timeout)
|
|
97
113
|
|
|
@@ -106,13 +122,12 @@ class TavilyClient:
|
|
|
106
122
|
|
|
107
123
|
if response.status_code == 429:
|
|
108
124
|
raise UsageLimitExceededError(detail)
|
|
109
|
-
elif response.status_code in [403,432,433]:
|
|
125
|
+
elif response.status_code in [403, 432, 433]:
|
|
110
126
|
raise ForbiddenError(detail)
|
|
111
127
|
elif response.status_code == 401:
|
|
112
128
|
raise InvalidAPIKeyError(detail)
|
|
113
129
|
elif response.status_code == 400:
|
|
114
130
|
raise BadRequestError(detail)
|
|
115
|
-
|
|
116
131
|
else:
|
|
117
132
|
raise response.raise_for_status()
|
|
118
133
|
|
|
@@ -160,13 +175,8 @@ class TavilyClient:
|
|
|
160
175
|
auto_parameters=auto_parameters,
|
|
161
176
|
include_favicon=include_favicon,
|
|
162
177
|
include_usage=include_usage,
|
|
163
|
-
**kwargs
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
tavily_results = response_dict.get("results", [])
|
|
167
|
-
|
|
168
|
-
response_dict["results"] = tavily_results
|
|
169
|
-
|
|
178
|
+
**kwargs)
|
|
179
|
+
response_dict.setdefault("results", [])
|
|
170
180
|
return response_dict
|
|
171
181
|
|
|
172
182
|
def _extract(self,
|
|
@@ -202,7 +212,7 @@ class TavilyClient:
|
|
|
202
212
|
data.update(kwargs)
|
|
203
213
|
|
|
204
214
|
try:
|
|
205
|
-
response =
|
|
215
|
+
response = self.session.post(self.base_url + "/extract", data=json.dumps(data), timeout=timeout)
|
|
206
216
|
except requests.exceptions.Timeout:
|
|
207
217
|
raise TimeoutError(timeout)
|
|
208
218
|
|
|
@@ -217,7 +227,7 @@ class TavilyClient:
|
|
|
217
227
|
|
|
218
228
|
if response.status_code == 429:
|
|
219
229
|
raise UsageLimitExceededError(detail)
|
|
220
|
-
elif response.status_code in [403,432,433]:
|
|
230
|
+
elif response.status_code in [403, 432, 433]:
|
|
221
231
|
raise ForbiddenError(detail)
|
|
222
232
|
elif response.status_code == 401:
|
|
223
233
|
raise InvalidAPIKeyError(detail)
|
|
@@ -251,13 +261,8 @@ class TavilyClient:
|
|
|
251
261
|
query=query,
|
|
252
262
|
chunks_per_source=chunks_per_source,
|
|
253
263
|
**kwargs)
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
failed_results = response_dict.get("failed_results", [])
|
|
257
|
-
|
|
258
|
-
response_dict["results"] = tavily_results
|
|
259
|
-
response_dict["failed_results"] = failed_results
|
|
260
|
-
|
|
264
|
+
response_dict.setdefault("results", [])
|
|
265
|
+
response_dict.setdefault("failed_results", [])
|
|
261
266
|
return response_dict
|
|
262
267
|
|
|
263
268
|
def _crawl(self,
|
|
@@ -310,8 +315,7 @@ class TavilyClient:
|
|
|
310
315
|
data = {k: v for k, v in data.items() if v is not None}
|
|
311
316
|
|
|
312
317
|
try:
|
|
313
|
-
response =
|
|
314
|
-
self.base_url + "/crawl", data=json.dumps(data), headers=self.headers, timeout=timeout, proxies=self.proxies)
|
|
318
|
+
response = self.session.post(self.base_url + "/crawl", data=json.dumps(data), timeout=timeout)
|
|
315
319
|
except requests.exceptions.Timeout:
|
|
316
320
|
raise TimeoutError(timeout)
|
|
317
321
|
|
|
@@ -326,7 +330,7 @@ class TavilyClient:
|
|
|
326
330
|
|
|
327
331
|
if response.status_code == 429:
|
|
328
332
|
raise UsageLimitExceededError(detail)
|
|
329
|
-
elif response.status_code in [403,432,433]:
|
|
333
|
+
elif response.status_code in [403, 432, 433]:
|
|
330
334
|
raise ForbiddenError(detail)
|
|
331
335
|
elif response.status_code == 401:
|
|
332
336
|
raise InvalidAPIKeyError(detail)
|
|
@@ -359,26 +363,24 @@ class TavilyClient:
|
|
|
359
363
|
Combined crawl method.
|
|
360
364
|
include_favicon: If True, include the favicon in the crawl results.
|
|
361
365
|
"""
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
return response_dict
|
|
366
|
+
return self._crawl(url,
|
|
367
|
+
max_depth=max_depth,
|
|
368
|
+
max_breadth=max_breadth,
|
|
369
|
+
limit=limit,
|
|
370
|
+
instructions=instructions,
|
|
371
|
+
select_paths=select_paths,
|
|
372
|
+
select_domains=select_domains,
|
|
373
|
+
exclude_paths=exclude_paths,
|
|
374
|
+
exclude_domains=exclude_domains,
|
|
375
|
+
allow_external=allow_external,
|
|
376
|
+
include_images=include_images,
|
|
377
|
+
extract_depth=extract_depth,
|
|
378
|
+
format=format,
|
|
379
|
+
timeout=timeout,
|
|
380
|
+
include_favicon=include_favicon,
|
|
381
|
+
include_usage=include_usage,
|
|
382
|
+
chunks_per_source=chunks_per_source,
|
|
383
|
+
**kwargs)
|
|
382
384
|
|
|
383
385
|
def _map(self,
|
|
384
386
|
url: str,
|
|
@@ -421,8 +423,7 @@ class TavilyClient:
|
|
|
421
423
|
data = {k: v for k, v in data.items() if v is not None}
|
|
422
424
|
|
|
423
425
|
try:
|
|
424
|
-
response =
|
|
425
|
-
self.base_url + "/map", data=json.dumps(data), headers=self.headers, timeout=timeout, proxies=self.proxies)
|
|
426
|
+
response = self.session.post(self.base_url + "/map", data=json.dumps(data), timeout=timeout)
|
|
426
427
|
except requests.exceptions.Timeout:
|
|
427
428
|
raise TimeoutError(timeout)
|
|
428
429
|
|
|
@@ -437,7 +438,7 @@ class TavilyClient:
|
|
|
437
438
|
|
|
438
439
|
if response.status_code == 429:
|
|
439
440
|
raise UsageLimitExceededError(detail)
|
|
440
|
-
elif response.status_code in [403,432,433]:
|
|
441
|
+
elif response.status_code in [403, 432, 433]:
|
|
441
442
|
raise ForbiddenError(detail)
|
|
442
443
|
elif response.status_code == 401:
|
|
443
444
|
raise InvalidAPIKeyError(detail)
|
|
@@ -466,26 +467,24 @@ class TavilyClient:
|
|
|
466
467
|
Combined map method.
|
|
467
468
|
|
|
468
469
|
"""
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
return response_dict
|
|
470
|
+
return self._map(url,
|
|
471
|
+
max_depth=max_depth,
|
|
472
|
+
max_breadth=max_breadth,
|
|
473
|
+
limit=limit,
|
|
474
|
+
instructions=instructions,
|
|
475
|
+
select_paths=select_paths,
|
|
476
|
+
select_domains=select_domains,
|
|
477
|
+
exclude_paths=exclude_paths,
|
|
478
|
+
exclude_domains=exclude_domains,
|
|
479
|
+
allow_external=allow_external,
|
|
480
|
+
include_images=include_images,
|
|
481
|
+
timeout=timeout,
|
|
482
|
+
include_usage=include_usage,
|
|
483
|
+
**kwargs)
|
|
485
484
|
|
|
486
485
|
def get_search_context(self,
|
|
487
486
|
query: str,
|
|
488
|
-
search_depth: Literal["basic", "advanced"] = "basic",
|
|
487
|
+
search_depth: Literal["basic", "advanced", "fast", "ultra-fast"] = "basic",
|
|
489
488
|
topic: Literal["general", "news", "finance"] = "general",
|
|
490
489
|
days: int = 7,
|
|
491
490
|
max_results: int = 5,
|
|
@@ -530,7 +529,7 @@ class TavilyClient:
|
|
|
530
529
|
|
|
531
530
|
def qna_search(self,
|
|
532
531
|
query: str,
|
|
533
|
-
search_depth: Literal["basic", "advanced"] = "advanced",
|
|
532
|
+
search_depth: Literal["basic", "advanced", "fast", "ultra-fast"] = "advanced",
|
|
534
533
|
topic: Literal["general", "news", "finance"] = "general",
|
|
535
534
|
days: int = 7,
|
|
536
535
|
max_results: int = 5,
|
|
@@ -563,45 +562,6 @@ class TavilyClient:
|
|
|
563
562
|
)
|
|
564
563
|
return response_dict.get("answer", "")
|
|
565
564
|
|
|
566
|
-
def get_company_info(self,
|
|
567
|
-
query: str,
|
|
568
|
-
search_depth: Literal["basic",
|
|
569
|
-
"advanced"] = "advanced",
|
|
570
|
-
max_results: int = 5,
|
|
571
|
-
timeout: float = 60,
|
|
572
|
-
country: str = None,
|
|
573
|
-
) -> Sequence[dict]:
|
|
574
|
-
""" Company information search method. Search depth is advanced by default to get the best answer. """
|
|
575
|
-
warnings.warn("get_company_info is deprecated and will be removed in future versions.",
|
|
576
|
-
DeprecationWarning, stacklevel=2)
|
|
577
|
-
def _perform_search(topic):
|
|
578
|
-
return self._search(query,
|
|
579
|
-
search_depth=search_depth,
|
|
580
|
-
topic=topic,
|
|
581
|
-
max_results=max_results,
|
|
582
|
-
include_answer=False,
|
|
583
|
-
timeout=timeout,
|
|
584
|
-
country=country)
|
|
585
|
-
|
|
586
|
-
with ThreadPoolExecutor() as executor:
|
|
587
|
-
# Initiate the search for each topic in parallel
|
|
588
|
-
future_to_topic = {executor.submit(_perform_search, topic): topic for topic in
|
|
589
|
-
["news", "general", "finance"]}
|
|
590
|
-
|
|
591
|
-
all_results = []
|
|
592
|
-
|
|
593
|
-
# Process the results as they become available
|
|
594
|
-
for future in as_completed(future_to_topic):
|
|
595
|
-
data = future.result()
|
|
596
|
-
if 'results' in data:
|
|
597
|
-
all_results.extend(data['results'])
|
|
598
|
-
|
|
599
|
-
# Sort all the results by score in descending order and take the top 'max_results' items
|
|
600
|
-
sorted_results = sorted(all_results, key=lambda x: x['score'], reverse=True)[
|
|
601
|
-
:max_results]
|
|
602
|
-
|
|
603
|
-
return sorted_results
|
|
604
|
-
|
|
605
565
|
def _research(self,
|
|
606
566
|
input: str,
|
|
607
567
|
model: Literal["mini", "pro", "auto"] = None,
|
|
@@ -629,12 +589,10 @@ class TavilyClient:
|
|
|
629
589
|
|
|
630
590
|
if stream:
|
|
631
591
|
try:
|
|
632
|
-
response =
|
|
592
|
+
response = self.session.post(
|
|
633
593
|
self.base_url + "/research",
|
|
634
594
|
data=json.dumps(data),
|
|
635
|
-
headers=self.headers,
|
|
636
595
|
timeout=timeout,
|
|
637
|
-
proxies=self.proxies,
|
|
638
596
|
stream=True
|
|
639
597
|
)
|
|
640
598
|
except requests.exceptions.Timeout:
|
|
@@ -649,7 +607,7 @@ class TavilyClient:
|
|
|
649
607
|
|
|
650
608
|
if response.status_code == 429:
|
|
651
609
|
raise UsageLimitExceededError(detail)
|
|
652
|
-
elif response.status_code in [403,432,433]:
|
|
610
|
+
elif response.status_code in [403, 432, 433]:
|
|
653
611
|
raise ForbiddenError(detail)
|
|
654
612
|
elif response.status_code == 401:
|
|
655
613
|
raise InvalidAPIKeyError(detail)
|
|
@@ -669,12 +627,10 @@ class TavilyClient:
|
|
|
669
627
|
return stream_generator()
|
|
670
628
|
else:
|
|
671
629
|
try:
|
|
672
|
-
response =
|
|
630
|
+
response = self.session.post(
|
|
673
631
|
self.base_url + "/research",
|
|
674
632
|
data=json.dumps(data),
|
|
675
|
-
|
|
676
|
-
timeout=timeout,
|
|
677
|
-
proxies=self.proxies
|
|
633
|
+
timeout=timeout
|
|
678
634
|
)
|
|
679
635
|
except requests.exceptions.Timeout:
|
|
680
636
|
raise TimeoutError(timeout)
|
|
@@ -690,7 +646,7 @@ class TavilyClient:
|
|
|
690
646
|
|
|
691
647
|
if response.status_code == 429:
|
|
692
648
|
raise UsageLimitExceededError(detail)
|
|
693
|
-
elif response.status_code in [403,432,433]:
|
|
649
|
+
elif response.status_code in [403, 432, 433]:
|
|
694
650
|
raise ForbiddenError(detail)
|
|
695
651
|
elif response.status_code == 401:
|
|
696
652
|
raise InvalidAPIKeyError(detail)
|
|
@@ -724,8 +680,7 @@ class TavilyClient:
|
|
|
724
680
|
dict: Response containing request_id, created_at, status, input, and model.
|
|
725
681
|
"""
|
|
726
682
|
|
|
727
|
-
|
|
728
|
-
response_dict = self._research(
|
|
683
|
+
return self._research(
|
|
729
684
|
input=input,
|
|
730
685
|
model=model,
|
|
731
686
|
output_schema=output_schema,
|
|
@@ -735,8 +690,6 @@ class TavilyClient:
|
|
|
735
690
|
**kwargs
|
|
736
691
|
)
|
|
737
692
|
|
|
738
|
-
return response_dict
|
|
739
|
-
|
|
740
693
|
def get_research(self,
|
|
741
694
|
request_id: str
|
|
742
695
|
) -> dict:
|
|
@@ -750,17 +703,12 @@ class TavilyClient:
|
|
|
750
703
|
dict: Research response containing request_id, created_at, completed_at, status, content, and sources.
|
|
751
704
|
"""
|
|
752
705
|
try:
|
|
753
|
-
response =
|
|
754
|
-
self.base_url + f"/research/{request_id}",
|
|
755
|
-
headers=self.headers,
|
|
756
|
-
proxies=self.proxies,
|
|
757
|
-
)
|
|
706
|
+
response = self.session.get(self.base_url + f"/research/{request_id}")
|
|
758
707
|
except Exception as e:
|
|
759
708
|
raise Exception(f"Error getting research: {e}")
|
|
760
709
|
|
|
761
710
|
if response.status_code in (200, 202):
|
|
762
|
-
|
|
763
|
-
return data
|
|
711
|
+
return response.json()
|
|
764
712
|
else:
|
|
765
713
|
detail = ""
|
|
766
714
|
try:
|
|
@@ -770,7 +718,7 @@ class TavilyClient:
|
|
|
770
718
|
|
|
771
719
|
if response.status_code == 429:
|
|
772
720
|
raise UsageLimitExceededError(detail)
|
|
773
|
-
elif response.status_code in [403,432,433]:
|
|
721
|
+
elif response.status_code in [403, 432, 433]:
|
|
774
722
|
raise ForbiddenError(detail)
|
|
775
723
|
elif response.status_code == 401:
|
|
776
724
|
raise InvalidAPIKeyError(detail)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|