exa-py 1.16.0__py3-none-any.whl → 2.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.
Potentially problematic release.
This version of exa-py might be problematic. Click here for more details.
- exa_py/api.py +219 -794
- exa_py/research/async_client.py +2 -1
- exa_py/research/models.py +6 -2
- exa_py/research/sync_client.py +5 -4
- {exa_py-1.16.0.dist-info → exa_py-2.0.0.dist-info}/METADATA +1 -1
- {exa_py-1.16.0.dist-info → exa_py-2.0.0.dist-info}/RECORD +7 -7
- {exa_py-1.16.0.dist-info → exa_py-2.0.0.dist-info}/WHEEL +0 -0
exa_py/api.py
CHANGED
|
@@ -47,6 +47,9 @@ from .research import ResearchClient, AsyncResearchClient
|
|
|
47
47
|
|
|
48
48
|
is_beta = os.getenv("IS_BETA") == "True"
|
|
49
49
|
|
|
50
|
+
# Default max characters for text contents
|
|
51
|
+
DEFAULT_MAX_CHARACTERS = 10_000
|
|
52
|
+
|
|
50
53
|
|
|
51
54
|
def snake_to_camel(snake_str: str) -> str:
|
|
52
55
|
"""Convert snake_case string to camelCase.
|
|
@@ -141,7 +144,6 @@ SEARCH_OPTIONS_TYPES = {
|
|
|
141
144
|
"exclude_text": [
|
|
142
145
|
list
|
|
143
146
|
], # Must not be present in webpage text. (One string, up to 5 words)
|
|
144
|
-
"use_autoprompt": [bool], # Convert query to Exa. (Default: false)
|
|
145
147
|
"type": [
|
|
146
148
|
str
|
|
147
149
|
], # 'keyword', 'neural', 'hybrid', 'fast', 'deep', or 'auto' (Default: auto)
|
|
@@ -150,6 +152,7 @@ SEARCH_OPTIONS_TYPES = {
|
|
|
150
152
|
], # A data category to focus on: 'company', 'research paper', 'news', 'pdf', 'github', 'tweet', 'personal site', 'linkedin profile', 'financial report'
|
|
151
153
|
"flags": [list], # Experimental flags array for Exa usage.
|
|
152
154
|
"moderation": [bool], # If true, moderate search results for safety.
|
|
155
|
+
"contents": [dict, bool], # Options for retrieving page contents
|
|
153
156
|
}
|
|
154
157
|
|
|
155
158
|
FIND_SIMILAR_OPTIONS_TYPES = {
|
|
@@ -166,6 +169,7 @@ FIND_SIMILAR_OPTIONS_TYPES = {
|
|
|
166
169
|
"exclude_source_domain": [bool],
|
|
167
170
|
"category": [str],
|
|
168
171
|
"flags": [list], # Experimental flags array for Exa usage.
|
|
172
|
+
"contents": [dict, bool], # Options for retrieving page contents
|
|
169
173
|
}
|
|
170
174
|
|
|
171
175
|
# the livecrawl options
|
|
@@ -174,7 +178,6 @@ LIVECRAWL_OPTIONS = Literal["always", "fallback", "never", "auto", "preferred"]
|
|
|
174
178
|
CONTENTS_OPTIONS_TYPES = {
|
|
175
179
|
"urls": [list],
|
|
176
180
|
"text": [dict, bool],
|
|
177
|
-
"highlights": [dict, bool],
|
|
178
181
|
"summary": [dict, bool],
|
|
179
182
|
"context": [dict, bool],
|
|
180
183
|
"metadata": [dict, bool],
|
|
@@ -255,24 +258,6 @@ class TextContentsOptions(TypedDict, total=False):
|
|
|
255
258
|
include_html_tags: bool
|
|
256
259
|
|
|
257
260
|
|
|
258
|
-
class HighlightsContentsOptions(TypedDict, total=False):
|
|
259
|
-
"""A class representing the options that you can specify when requesting highlights
|
|
260
|
-
|
|
261
|
-
Attributes:
|
|
262
|
-
query (str): The query string for the highlights.
|
|
263
|
-
num_sentences (int): Size of highlights to return, in sentences. Default: 5
|
|
264
|
-
highlights_per_url (int): Number of highlights to return per URL. Default: 1
|
|
265
|
-
|
|
266
|
-
NOTE: When using the "deep" search type, only the default highlights=True is supported.
|
|
267
|
-
These options will NOT be respected. Highlights will always be based on the user's query,
|
|
268
|
-
and the number and length may vary.
|
|
269
|
-
"""
|
|
270
|
-
|
|
271
|
-
query: str
|
|
272
|
-
num_sentences: int
|
|
273
|
-
highlights_per_url: int
|
|
274
|
-
|
|
275
|
-
|
|
276
261
|
class JSONSchema(TypedDict, total=False):
|
|
277
262
|
"""Represents a JSON Schema definition used for structured summary output.
|
|
278
263
|
|
|
@@ -341,7 +326,6 @@ class CostDollarsContents(TypedDict, total=False):
|
|
|
341
326
|
"""Represents the cost breakdown for contents."""
|
|
342
327
|
|
|
343
328
|
text: float
|
|
344
|
-
highlights: float
|
|
345
329
|
summary: float
|
|
346
330
|
|
|
347
331
|
|
|
@@ -424,18 +408,14 @@ class _Result:
|
|
|
424
408
|
@dataclass
|
|
425
409
|
class Result(_Result):
|
|
426
410
|
"""
|
|
427
|
-
A class representing a search result with optional text
|
|
411
|
+
A class representing a search result with optional text and summary.
|
|
428
412
|
|
|
429
413
|
Attributes:
|
|
430
414
|
text (str, optional)
|
|
431
|
-
highlights (List[str], optional)
|
|
432
|
-
highlight_scores (List[float], optional)
|
|
433
415
|
summary (str, optional)
|
|
434
416
|
"""
|
|
435
417
|
|
|
436
418
|
text: Optional[str] = None
|
|
437
|
-
highlights: Optional[List[str]] = None
|
|
438
|
-
highlight_scores: Optional[List[float]] = None
|
|
439
419
|
summary: Optional[str] = None
|
|
440
420
|
|
|
441
421
|
def __init__(
|
|
@@ -451,9 +431,9 @@ class Result(_Result):
|
|
|
451
431
|
subpages=None,
|
|
452
432
|
extras=None,
|
|
453
433
|
text=None,
|
|
454
|
-
highlights=None,
|
|
455
|
-
highlight_scores=None,
|
|
456
434
|
summary=None,
|
|
435
|
+
highlights=None, # Deprecated, for backward compatibility
|
|
436
|
+
highlight_scores=None, # Deprecated, for backward compatibility
|
|
457
437
|
):
|
|
458
438
|
super().__init__(
|
|
459
439
|
url,
|
|
@@ -468,18 +448,11 @@ class Result(_Result):
|
|
|
468
448
|
extras,
|
|
469
449
|
)
|
|
470
450
|
self.text = text
|
|
471
|
-
self.highlights = highlights
|
|
472
|
-
self.highlight_scores = highlight_scores
|
|
473
451
|
self.summary = summary
|
|
474
452
|
|
|
475
453
|
def __str__(self):
|
|
476
454
|
base_str = super().__str__()
|
|
477
|
-
return base_str + (
|
|
478
|
-
f"Text: {self.text}\n"
|
|
479
|
-
f"Highlights: {self.highlights}\n"
|
|
480
|
-
f"Highlight Scores: {self.highlight_scores}\n"
|
|
481
|
-
f"Summary: {self.summary}\n"
|
|
482
|
-
)
|
|
455
|
+
return base_str + (f"Text: {self.text}\nSummary: {self.summary}\n")
|
|
483
456
|
|
|
484
457
|
|
|
485
458
|
@dataclass
|
|
@@ -526,113 +499,6 @@ class ResultWithText(_Result):
|
|
|
526
499
|
return base_str + f"Text: {self.text}\n"
|
|
527
500
|
|
|
528
501
|
|
|
529
|
-
@dataclass
|
|
530
|
-
class ResultWithHighlights(_Result):
|
|
531
|
-
"""
|
|
532
|
-
A class representing a search result with highlights present.
|
|
533
|
-
|
|
534
|
-
Attributes:
|
|
535
|
-
highlights (List[str])
|
|
536
|
-
highlight_scores (List[float])
|
|
537
|
-
"""
|
|
538
|
-
|
|
539
|
-
highlights: List[str] = dataclasses.field(default_factory=list)
|
|
540
|
-
highlight_scores: List[float] = dataclasses.field(default_factory=list)
|
|
541
|
-
|
|
542
|
-
def __init__(
|
|
543
|
-
self,
|
|
544
|
-
url,
|
|
545
|
-
id,
|
|
546
|
-
title=None,
|
|
547
|
-
score=None,
|
|
548
|
-
published_date=None,
|
|
549
|
-
author=None,
|
|
550
|
-
image=None,
|
|
551
|
-
favicon=None,
|
|
552
|
-
subpages=None,
|
|
553
|
-
extras=None,
|
|
554
|
-
highlights=None,
|
|
555
|
-
highlight_scores=None,
|
|
556
|
-
):
|
|
557
|
-
super().__init__(
|
|
558
|
-
url,
|
|
559
|
-
id,
|
|
560
|
-
title,
|
|
561
|
-
score,
|
|
562
|
-
published_date,
|
|
563
|
-
author,
|
|
564
|
-
image,
|
|
565
|
-
favicon,
|
|
566
|
-
subpages,
|
|
567
|
-
extras,
|
|
568
|
-
)
|
|
569
|
-
self.highlights = highlights if highlights is not None else []
|
|
570
|
-
self.highlight_scores = highlight_scores if highlight_scores is not None else []
|
|
571
|
-
|
|
572
|
-
def __str__(self):
|
|
573
|
-
base_str = super().__str__()
|
|
574
|
-
return base_str + (
|
|
575
|
-
f"Highlights: {self.highlights}\n"
|
|
576
|
-
f"Highlight Scores: {self.highlight_scores}\n"
|
|
577
|
-
)
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
@dataclass
|
|
581
|
-
class ResultWithTextAndHighlights(_Result):
|
|
582
|
-
"""
|
|
583
|
-
A class representing a search result with text and highlights present.
|
|
584
|
-
|
|
585
|
-
Attributes:
|
|
586
|
-
text (str)
|
|
587
|
-
highlights (List[str])
|
|
588
|
-
highlight_scores (List[float])
|
|
589
|
-
"""
|
|
590
|
-
|
|
591
|
-
text: str = dataclasses.field(default_factory=str)
|
|
592
|
-
highlights: List[str] = dataclasses.field(default_factory=list)
|
|
593
|
-
highlight_scores: List[float] = dataclasses.field(default_factory=list)
|
|
594
|
-
|
|
595
|
-
def __init__(
|
|
596
|
-
self,
|
|
597
|
-
url,
|
|
598
|
-
id,
|
|
599
|
-
title=None,
|
|
600
|
-
score=None,
|
|
601
|
-
published_date=None,
|
|
602
|
-
author=None,
|
|
603
|
-
image=None,
|
|
604
|
-
favicon=None,
|
|
605
|
-
subpages=None,
|
|
606
|
-
extras=None,
|
|
607
|
-
text="",
|
|
608
|
-
highlights=None,
|
|
609
|
-
highlight_scores=None,
|
|
610
|
-
):
|
|
611
|
-
super().__init__(
|
|
612
|
-
url,
|
|
613
|
-
id,
|
|
614
|
-
title,
|
|
615
|
-
score,
|
|
616
|
-
published_date,
|
|
617
|
-
author,
|
|
618
|
-
image,
|
|
619
|
-
favicon,
|
|
620
|
-
subpages,
|
|
621
|
-
extras,
|
|
622
|
-
)
|
|
623
|
-
self.text = text
|
|
624
|
-
self.highlights = highlights if highlights is not None else []
|
|
625
|
-
self.highlight_scores = highlight_scores if highlight_scores is not None else []
|
|
626
|
-
|
|
627
|
-
def __str__(self):
|
|
628
|
-
base_str = super().__str__()
|
|
629
|
-
return base_str + (
|
|
630
|
-
f"Text: {self.text}\n"
|
|
631
|
-
f"Highlights: {self.highlights}\n"
|
|
632
|
-
f"Highlight Scores: {self.highlight_scores}\n"
|
|
633
|
-
)
|
|
634
|
-
|
|
635
|
-
|
|
636
502
|
@dataclass
|
|
637
503
|
class ResultWithSummary(_Result):
|
|
638
504
|
"""
|
|
@@ -725,123 +591,6 @@ class ResultWithTextAndSummary(_Result):
|
|
|
725
591
|
return base_str + f"Text: {self.text}\n" + f"Summary: {self.summary}\n"
|
|
726
592
|
|
|
727
593
|
|
|
728
|
-
@dataclass
|
|
729
|
-
class ResultWithHighlightsAndSummary(_Result):
|
|
730
|
-
"""
|
|
731
|
-
A class representing a search result with highlights and summary present.
|
|
732
|
-
|
|
733
|
-
Attributes:
|
|
734
|
-
highlights (List[str])
|
|
735
|
-
highlight_scores (List[float])
|
|
736
|
-
summary (str)
|
|
737
|
-
"""
|
|
738
|
-
|
|
739
|
-
highlights: List[str] = dataclasses.field(default_factory=list)
|
|
740
|
-
highlight_scores: List[float] = dataclasses.field(default_factory=list)
|
|
741
|
-
summary: str = dataclasses.field(default_factory=str)
|
|
742
|
-
|
|
743
|
-
def __init__(
|
|
744
|
-
self,
|
|
745
|
-
url,
|
|
746
|
-
id,
|
|
747
|
-
title=None,
|
|
748
|
-
score=None,
|
|
749
|
-
published_date=None,
|
|
750
|
-
author=None,
|
|
751
|
-
image=None,
|
|
752
|
-
favicon=None,
|
|
753
|
-
subpages=None,
|
|
754
|
-
extras=None,
|
|
755
|
-
highlights=None,
|
|
756
|
-
highlight_scores=None,
|
|
757
|
-
summary="",
|
|
758
|
-
):
|
|
759
|
-
super().__init__(
|
|
760
|
-
url,
|
|
761
|
-
id,
|
|
762
|
-
title,
|
|
763
|
-
score,
|
|
764
|
-
published_date,
|
|
765
|
-
author,
|
|
766
|
-
image,
|
|
767
|
-
favicon,
|
|
768
|
-
subpages,
|
|
769
|
-
extras,
|
|
770
|
-
)
|
|
771
|
-
self.highlights = highlights if highlights is not None else []
|
|
772
|
-
self.highlight_scores = highlight_scores if highlight_scores is not None else []
|
|
773
|
-
self.summary = summary
|
|
774
|
-
|
|
775
|
-
def __str__(self):
|
|
776
|
-
base_str = super().__str__()
|
|
777
|
-
return base_str + (
|
|
778
|
-
f"Highlights: {self.highlights}\n"
|
|
779
|
-
f"Highlight Scores: {self.highlight_scores}\n"
|
|
780
|
-
f"Summary: {self.summary}\n"
|
|
781
|
-
)
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
@dataclass
|
|
785
|
-
class ResultWithTextAndHighlightsAndSummary(_Result):
|
|
786
|
-
"""
|
|
787
|
-
A class representing a search result with text, highlights, and summary present.
|
|
788
|
-
|
|
789
|
-
Attributes:
|
|
790
|
-
text (str)
|
|
791
|
-
highlights (List[str])
|
|
792
|
-
highlight_scores (List[float])
|
|
793
|
-
summary (str)
|
|
794
|
-
"""
|
|
795
|
-
|
|
796
|
-
text: str = dataclasses.field(default_factory=str)
|
|
797
|
-
highlights: List[str] = dataclasses.field(default_factory=list)
|
|
798
|
-
highlight_scores: List[float] = dataclasses.field(default_factory=list)
|
|
799
|
-
summary: str = dataclasses.field(default_factory=str)
|
|
800
|
-
|
|
801
|
-
def __init__(
|
|
802
|
-
self,
|
|
803
|
-
url,
|
|
804
|
-
id,
|
|
805
|
-
title=None,
|
|
806
|
-
score=None,
|
|
807
|
-
published_date=None,
|
|
808
|
-
author=None,
|
|
809
|
-
image=None,
|
|
810
|
-
favicon=None,
|
|
811
|
-
subpages=None,
|
|
812
|
-
extras=None,
|
|
813
|
-
text="",
|
|
814
|
-
highlights=None,
|
|
815
|
-
highlight_scores=None,
|
|
816
|
-
summary="",
|
|
817
|
-
):
|
|
818
|
-
super().__init__(
|
|
819
|
-
url,
|
|
820
|
-
id,
|
|
821
|
-
title,
|
|
822
|
-
score,
|
|
823
|
-
published_date,
|
|
824
|
-
author,
|
|
825
|
-
image,
|
|
826
|
-
favicon,
|
|
827
|
-
subpages,
|
|
828
|
-
extras,
|
|
829
|
-
)
|
|
830
|
-
self.text = text
|
|
831
|
-
self.highlights = highlights if highlights is not None else []
|
|
832
|
-
self.highlight_scores = highlight_scores if highlight_scores is not None else []
|
|
833
|
-
self.summary = summary
|
|
834
|
-
|
|
835
|
-
def __str__(self):
|
|
836
|
-
base_str = super().__str__()
|
|
837
|
-
return base_str + (
|
|
838
|
-
f"Text: {self.text}\n"
|
|
839
|
-
f"Highlights: {self.highlights}\n"
|
|
840
|
-
f"Highlight Scores: {self.highlight_scores}\n"
|
|
841
|
-
f"Summary: {self.summary}\n"
|
|
842
|
-
)
|
|
843
|
-
|
|
844
|
-
|
|
845
594
|
@dataclass
|
|
846
595
|
class AnswerResult:
|
|
847
596
|
"""A class representing a result for an answer.
|
|
@@ -1073,7 +822,6 @@ class SearchResponse(Generic[T]):
|
|
|
1073
822
|
|
|
1074
823
|
Attributes:
|
|
1075
824
|
results (List[Result]): A list of search results.
|
|
1076
|
-
autoprompt_string (str, optional): The Exa query created by autoprompt.
|
|
1077
825
|
resolved_search_type (str, optional): 'neural' or 'keyword' if auto.
|
|
1078
826
|
auto_date (str, optional): A date for filtering if autoprompt found one.
|
|
1079
827
|
context (str, optional): Combined context string when requested via contents.context.
|
|
@@ -1082,7 +830,6 @@ class SearchResponse(Generic[T]):
|
|
|
1082
830
|
"""
|
|
1083
831
|
|
|
1084
832
|
results: List[T]
|
|
1085
|
-
autoprompt_string: Optional[str]
|
|
1086
833
|
resolved_search_type: Optional[str]
|
|
1087
834
|
auto_date: Optional[str]
|
|
1088
835
|
context: Optional[str] = None
|
|
@@ -1093,8 +840,6 @@ class SearchResponse(Generic[T]):
|
|
|
1093
840
|
output = "\n\n".join(str(result) for result in self.results)
|
|
1094
841
|
if self.context:
|
|
1095
842
|
output += f"\nContext: {self.context}"
|
|
1096
|
-
if self.autoprompt_string:
|
|
1097
|
-
output += f"\n\nAutoprompt String: {self.autoprompt_string}"
|
|
1098
843
|
if self.resolved_search_type:
|
|
1099
844
|
output += f"\nResolved Search Type: {self.resolved_search_type}"
|
|
1100
845
|
if self.cost_dollars:
|
|
@@ -1230,312 +975,28 @@ class Exa:
|
|
|
1230
975
|
return res
|
|
1231
976
|
else:
|
|
1232
977
|
res = requests.post(
|
|
1233
|
-
self.base_url + endpoint, data=json_data, headers=request_headers
|
|
1234
|
-
)
|
|
1235
|
-
elif method.upper() == "PATCH":
|
|
1236
|
-
res = requests.patch(
|
|
1237
|
-
self.base_url + endpoint, data=json_data, headers=request_headers
|
|
1238
|
-
)
|
|
1239
|
-
elif method.upper() == "DELETE":
|
|
1240
|
-
res = requests.delete(self.base_url + endpoint, headers=request_headers)
|
|
1241
|
-
else:
|
|
1242
|
-
raise ValueError(f"Unsupported HTTP method: {method}")
|
|
1243
|
-
|
|
1244
|
-
if res.status_code >= 400:
|
|
1245
|
-
raise ValueError(
|
|
1246
|
-
f"Request failed with status code {res.status_code}: {res.text}"
|
|
1247
|
-
)
|
|
1248
|
-
return res.json()
|
|
1249
|
-
|
|
1250
|
-
def search(
|
|
1251
|
-
self,
|
|
1252
|
-
query: str,
|
|
1253
|
-
*,
|
|
1254
|
-
num_results: Optional[int] = None,
|
|
1255
|
-
include_domains: Optional[List[str]] = None,
|
|
1256
|
-
exclude_domains: Optional[List[str]] = None,
|
|
1257
|
-
start_crawl_date: Optional[str] = None,
|
|
1258
|
-
end_crawl_date: Optional[str] = None,
|
|
1259
|
-
start_published_date: Optional[str] = None,
|
|
1260
|
-
end_published_date: Optional[str] = None,
|
|
1261
|
-
include_text: Optional[List[str]] = None,
|
|
1262
|
-
exclude_text: Optional[List[str]] = None,
|
|
1263
|
-
use_autoprompt: Optional[bool] = None,
|
|
1264
|
-
type: Optional[str] = None,
|
|
1265
|
-
category: Optional[str] = None,
|
|
1266
|
-
flags: Optional[List[str]] = None,
|
|
1267
|
-
moderation: Optional[bool] = None,
|
|
1268
|
-
user_location: Optional[str] = None,
|
|
1269
|
-
) -> SearchResponse[_Result]:
|
|
1270
|
-
"""Perform a search with a prompt-engineered query to retrieve relevant results.
|
|
1271
|
-
|
|
1272
|
-
Args:
|
|
1273
|
-
query (str): The query string.
|
|
1274
|
-
num_results (int, optional): Number of search results to return (default 10).
|
|
1275
|
-
include_domains (List[str], optional): Domains to include in the search.
|
|
1276
|
-
exclude_domains (List[str], optional): Domains to exclude from the search.
|
|
1277
|
-
start_crawl_date (str, optional): Only links crawled after this date.
|
|
1278
|
-
end_crawl_date (str, optional): Only links crawled before this date.
|
|
1279
|
-
start_published_date (str, optional): Only links published after this date.
|
|
1280
|
-
end_published_date (str, optional): Only links published before this date.
|
|
1281
|
-
include_text (List[str], optional): Strings that must appear in the page text.
|
|
1282
|
-
exclude_text (List[str], optional): Strings that must not appear in the page text.
|
|
1283
|
-
use_autoprompt (bool, optional): Convert query to Exa (default False).
|
|
1284
|
-
type (str, optional): 'keyword', 'neural', 'hybrid', 'fast', 'deep', or 'auto' (default 'auto').
|
|
1285
|
-
category (str, optional): e.g. 'company'
|
|
1286
|
-
flags (List[str], optional): Experimental flags for Exa usage.
|
|
1287
|
-
moderation (bool, optional): If True, the search results will be moderated for safety.
|
|
1288
|
-
user_location (str, optional): Two-letter ISO country code of the user (e.g. US).
|
|
1289
|
-
|
|
1290
|
-
Returns:
|
|
1291
|
-
SearchResponse: The response containing search results, etc.
|
|
1292
|
-
"""
|
|
1293
|
-
options = {k: v for k, v in locals().items() if k != "self" and v is not None}
|
|
1294
|
-
validate_search_options(options, SEARCH_OPTIONS_TYPES)
|
|
1295
|
-
options = to_camel_case(options)
|
|
1296
|
-
data = self.request("/search", options)
|
|
1297
|
-
cost_dollars = parse_cost_dollars(data.get("costDollars"))
|
|
1298
|
-
results = []
|
|
1299
|
-
for result in data["results"]:
|
|
1300
|
-
snake_result = to_snake_case(result)
|
|
1301
|
-
results.append(
|
|
1302
|
-
Result(
|
|
1303
|
-
url=snake_result.get("url"),
|
|
1304
|
-
id=snake_result.get("id"),
|
|
1305
|
-
title=snake_result.get("title"),
|
|
1306
|
-
score=snake_result.get("score"),
|
|
1307
|
-
published_date=snake_result.get("published_date"),
|
|
1308
|
-
author=snake_result.get("author"),
|
|
1309
|
-
image=snake_result.get("image"),
|
|
1310
|
-
favicon=snake_result.get("favicon"),
|
|
1311
|
-
subpages=snake_result.get("subpages"),
|
|
1312
|
-
extras=snake_result.get("extras"),
|
|
1313
|
-
text=snake_result.get("text"),
|
|
1314
|
-
highlights=snake_result.get("highlights"),
|
|
1315
|
-
highlight_scores=snake_result.get("highlight_scores"),
|
|
1316
|
-
summary=snake_result.get("summary"),
|
|
1317
|
-
)
|
|
1318
|
-
)
|
|
1319
|
-
return SearchResponse(
|
|
1320
|
-
results,
|
|
1321
|
-
data["autopromptString"] if "autopromptString" in data else None,
|
|
1322
|
-
data["resolvedSearchType"] if "resolvedSearchType" in data else None,
|
|
1323
|
-
data["autoDate"] if "autoDate" in data else None,
|
|
1324
|
-
cost_dollars=cost_dollars,
|
|
1325
|
-
)
|
|
1326
|
-
|
|
1327
|
-
@overload
|
|
1328
|
-
def search_and_contents(
|
|
1329
|
-
self,
|
|
1330
|
-
query: str,
|
|
1331
|
-
*,
|
|
1332
|
-
num_results: Optional[int] = None,
|
|
1333
|
-
include_domains: Optional[List[str]] = None,
|
|
1334
|
-
exclude_domains: Optional[List[str]] = None,
|
|
1335
|
-
start_crawl_date: Optional[str] = None,
|
|
1336
|
-
end_crawl_date: Optional[str] = None,
|
|
1337
|
-
start_published_date: Optional[str] = None,
|
|
1338
|
-
end_published_date: Optional[str] = None,
|
|
1339
|
-
include_text: Optional[List[str]] = None,
|
|
1340
|
-
exclude_text: Optional[List[str]] = None,
|
|
1341
|
-
use_autoprompt: Optional[bool] = None,
|
|
1342
|
-
type: Optional[str] = None,
|
|
1343
|
-
category: Optional[str] = None,
|
|
1344
|
-
flags: Optional[List[str]] = None,
|
|
1345
|
-
moderation: Optional[bool] = None,
|
|
1346
|
-
user_location: Optional[str] = None,
|
|
1347
|
-
livecrawl_timeout: Optional[int] = None,
|
|
1348
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1349
|
-
filter_empty_results: Optional[bool] = None,
|
|
1350
|
-
subpages: Optional[int] = None,
|
|
1351
|
-
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1352
|
-
extras: Optional[ExtrasOptions] = None,
|
|
1353
|
-
) -> SearchResponse[ResultWithText]: ...
|
|
1354
|
-
|
|
1355
|
-
@overload
|
|
1356
|
-
def search_and_contents(
|
|
1357
|
-
self,
|
|
1358
|
-
query: str,
|
|
1359
|
-
*,
|
|
1360
|
-
text: Union[TextContentsOptions, Literal[True]],
|
|
1361
|
-
num_results: Optional[int] = None,
|
|
1362
|
-
include_domains: Optional[List[str]] = None,
|
|
1363
|
-
exclude_domains: Optional[List[str]] = None,
|
|
1364
|
-
start_crawl_date: Optional[str] = None,
|
|
1365
|
-
end_crawl_date: Optional[str] = None,
|
|
1366
|
-
start_published_date: Optional[str] = None,
|
|
1367
|
-
end_published_date: Optional[str] = None,
|
|
1368
|
-
include_text: Optional[List[str]] = None,
|
|
1369
|
-
exclude_text: Optional[List[str]] = None,
|
|
1370
|
-
use_autoprompt: Optional[bool] = None,
|
|
1371
|
-
type: Optional[str] = None,
|
|
1372
|
-
category: Optional[str] = None,
|
|
1373
|
-
flags: Optional[List[str]] = None,
|
|
1374
|
-
moderation: Optional[bool] = None,
|
|
1375
|
-
subpages: Optional[int] = None,
|
|
1376
|
-
livecrawl_timeout: Optional[int] = None,
|
|
1377
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1378
|
-
filter_empty_results: Optional[bool] = None,
|
|
1379
|
-
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1380
|
-
extras: Optional[ExtrasOptions] = None,
|
|
1381
|
-
) -> SearchResponse[ResultWithText]: ...
|
|
1382
|
-
|
|
1383
|
-
@overload
|
|
1384
|
-
def search_and_contents(
|
|
1385
|
-
self,
|
|
1386
|
-
query: str,
|
|
1387
|
-
*,
|
|
1388
|
-
highlights: Union[HighlightsContentsOptions, Literal[True]],
|
|
1389
|
-
num_results: Optional[int] = None,
|
|
1390
|
-
include_domains: Optional[List[str]] = None,
|
|
1391
|
-
exclude_domains: Optional[List[str]] = None,
|
|
1392
|
-
start_crawl_date: Optional[str] = None,
|
|
1393
|
-
end_crawl_date: Optional[str] = None,
|
|
1394
|
-
start_published_date: Optional[str] = None,
|
|
1395
|
-
end_published_date: Optional[str] = None,
|
|
1396
|
-
include_text: Optional[List[str]] = None,
|
|
1397
|
-
exclude_text: Optional[List[str]] = None,
|
|
1398
|
-
use_autoprompt: Optional[bool] = None,
|
|
1399
|
-
type: Optional[str] = None,
|
|
1400
|
-
category: Optional[str] = None,
|
|
1401
|
-
subpages: Optional[int] = None,
|
|
1402
|
-
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1403
|
-
flags: Optional[List[str]] = None,
|
|
1404
|
-
moderation: Optional[bool] = None,
|
|
1405
|
-
user_location: Optional[str] = None,
|
|
1406
|
-
livecrawl_timeout: Optional[int] = None,
|
|
1407
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1408
|
-
filter_empty_results: Optional[bool] = None,
|
|
1409
|
-
extras: Optional[ExtrasOptions] = None,
|
|
1410
|
-
) -> SearchResponse[ResultWithHighlights]: ...
|
|
1411
|
-
|
|
1412
|
-
@overload
|
|
1413
|
-
def search_and_contents(
|
|
1414
|
-
self,
|
|
1415
|
-
query: str,
|
|
1416
|
-
*,
|
|
1417
|
-
text: Union[TextContentsOptions, Literal[True]],
|
|
1418
|
-
highlights: Union[HighlightsContentsOptions, Literal[True]],
|
|
1419
|
-
num_results: Optional[int] = None,
|
|
1420
|
-
include_domains: Optional[List[str]] = None,
|
|
1421
|
-
exclude_domains: Optional[List[str]] = None,
|
|
1422
|
-
start_crawl_date: Optional[str] = None,
|
|
1423
|
-
end_crawl_date: Optional[str] = None,
|
|
1424
|
-
start_published_date: Optional[str] = None,
|
|
1425
|
-
end_published_date: Optional[str] = None,
|
|
1426
|
-
include_text: Optional[List[str]] = None,
|
|
1427
|
-
exclude_text: Optional[List[str]] = None,
|
|
1428
|
-
use_autoprompt: Optional[bool] = None,
|
|
1429
|
-
type: Optional[str] = None,
|
|
1430
|
-
category: Optional[str] = None,
|
|
1431
|
-
subpages: Optional[int] = None,
|
|
1432
|
-
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1433
|
-
flags: Optional[List[str]] = None,
|
|
1434
|
-
moderation: Optional[bool] = None,
|
|
1435
|
-
user_location: Optional[str] = None,
|
|
1436
|
-
livecrawl_timeout: Optional[int] = None,
|
|
1437
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1438
|
-
filter_empty_results: Optional[bool] = None,
|
|
1439
|
-
extras: Optional[ExtrasOptions] = None,
|
|
1440
|
-
) -> SearchResponse[ResultWithTextAndHighlights]: ...
|
|
1441
|
-
|
|
1442
|
-
@overload
|
|
1443
|
-
def search_and_contents(
|
|
1444
|
-
self,
|
|
1445
|
-
query: str,
|
|
1446
|
-
*,
|
|
1447
|
-
summary: Union[SummaryContentsOptions, Literal[True]],
|
|
1448
|
-
num_results: Optional[int] = None,
|
|
1449
|
-
include_domains: Optional[List[str]] = None,
|
|
1450
|
-
exclude_domains: Optional[List[str]] = None,
|
|
1451
|
-
start_crawl_date: Optional[str] = None,
|
|
1452
|
-
end_crawl_date: Optional[str] = None,
|
|
1453
|
-
start_published_date: Optional[str] = None,
|
|
1454
|
-
end_published_date: Optional[str] = None,
|
|
1455
|
-
include_text: Optional[List[str]] = None,
|
|
1456
|
-
exclude_text: Optional[List[str]] = None,
|
|
1457
|
-
use_autoprompt: Optional[bool] = None,
|
|
1458
|
-
type: Optional[str] = None,
|
|
1459
|
-
category: Optional[str] = None,
|
|
1460
|
-
subpages: Optional[int] = None,
|
|
1461
|
-
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1462
|
-
flags: Optional[List[str]] = None,
|
|
1463
|
-
moderation: Optional[bool] = None,
|
|
1464
|
-
user_location: Optional[str] = None,
|
|
1465
|
-
livecrawl_timeout: Optional[int] = None,
|
|
1466
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1467
|
-
filter_empty_results: Optional[bool] = None,
|
|
1468
|
-
extras: Optional[ExtrasOptions] = None,
|
|
1469
|
-
) -> SearchResponse[ResultWithSummary]: ...
|
|
1470
|
-
|
|
1471
|
-
@overload
|
|
1472
|
-
def search_and_contents(
|
|
1473
|
-
self,
|
|
1474
|
-
query: str,
|
|
1475
|
-
*,
|
|
1476
|
-
text: Union[TextContentsOptions, Literal[True]],
|
|
1477
|
-
summary: Union[SummaryContentsOptions, Literal[True]],
|
|
1478
|
-
num_results: Optional[int] = None,
|
|
1479
|
-
include_domains: Optional[List[str]] = None,
|
|
1480
|
-
exclude_domains: Optional[List[str]] = None,
|
|
1481
|
-
start_crawl_date: Optional[str] = None,
|
|
1482
|
-
end_crawl_date: Optional[str] = None,
|
|
1483
|
-
start_published_date: Optional[str] = None,
|
|
1484
|
-
end_published_date: Optional[str] = None,
|
|
1485
|
-
include_text: Optional[List[str]] = None,
|
|
1486
|
-
exclude_text: Optional[List[str]] = None,
|
|
1487
|
-
use_autoprompt: Optional[bool] = None,
|
|
1488
|
-
type: Optional[str] = None,
|
|
1489
|
-
category: Optional[str] = None,
|
|
1490
|
-
subpages: Optional[int] = None,
|
|
1491
|
-
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1492
|
-
flags: Optional[List[str]] = None,
|
|
1493
|
-
moderation: Optional[bool] = None,
|
|
1494
|
-
user_location: Optional[str] = None,
|
|
1495
|
-
livecrawl_timeout: Optional[int] = None,
|
|
1496
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1497
|
-
filter_empty_results: Optional[bool] = None,
|
|
1498
|
-
extras: Optional[ExtrasOptions] = None,
|
|
1499
|
-
) -> SearchResponse[ResultWithTextAndSummary]: ...
|
|
1500
|
-
|
|
1501
|
-
@overload
|
|
1502
|
-
def search_and_contents(
|
|
1503
|
-
self,
|
|
1504
|
-
query: str,
|
|
1505
|
-
*,
|
|
1506
|
-
highlights: Union[HighlightsContentsOptions, Literal[True]],
|
|
1507
|
-
summary: Union[SummaryContentsOptions, Literal[True]],
|
|
1508
|
-
num_results: Optional[int] = None,
|
|
1509
|
-
include_domains: Optional[List[str]] = None,
|
|
1510
|
-
exclude_domains: Optional[List[str]] = None,
|
|
1511
|
-
start_crawl_date: Optional[str] = None,
|
|
1512
|
-
end_crawl_date: Optional[str] = None,
|
|
1513
|
-
start_published_date: Optional[str] = None,
|
|
1514
|
-
end_published_date: Optional[str] = None,
|
|
1515
|
-
include_text: Optional[List[str]] = None,
|
|
1516
|
-
exclude_text: Optional[List[str]] = None,
|
|
1517
|
-
use_autoprompt: Optional[bool] = None,
|
|
1518
|
-
type: Optional[str] = None,
|
|
1519
|
-
category: Optional[str] = None,
|
|
1520
|
-
subpages: Optional[int] = None,
|
|
1521
|
-
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1522
|
-
flags: Optional[List[str]] = None,
|
|
1523
|
-
moderation: Optional[bool] = None,
|
|
1524
|
-
user_location: Optional[str] = None,
|
|
1525
|
-
livecrawl_timeout: Optional[int] = None,
|
|
1526
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1527
|
-
filter_empty_results: Optional[bool] = None,
|
|
1528
|
-
extras: Optional[ExtrasOptions] = None,
|
|
1529
|
-
) -> SearchResponse[ResultWithHighlightsAndSummary]: ...
|
|
978
|
+
self.base_url + endpoint, data=json_data, headers=request_headers
|
|
979
|
+
)
|
|
980
|
+
elif method.upper() == "PATCH":
|
|
981
|
+
res = requests.patch(
|
|
982
|
+
self.base_url + endpoint, data=json_data, headers=request_headers
|
|
983
|
+
)
|
|
984
|
+
elif method.upper() == "DELETE":
|
|
985
|
+
res = requests.delete(self.base_url + endpoint, headers=request_headers)
|
|
986
|
+
else:
|
|
987
|
+
raise ValueError(f"Unsupported HTTP method: {method}")
|
|
1530
988
|
|
|
1531
|
-
|
|
1532
|
-
|
|
989
|
+
if res.status_code >= 400:
|
|
990
|
+
raise ValueError(
|
|
991
|
+
f"Request failed with status code {res.status_code}: {res.text}"
|
|
992
|
+
)
|
|
993
|
+
return res.json()
|
|
994
|
+
|
|
995
|
+
def search(
|
|
1533
996
|
self,
|
|
1534
997
|
query: str,
|
|
1535
998
|
*,
|
|
1536
|
-
|
|
1537
|
-
highlights: Union[HighlightsContentsOptions, Literal[True]],
|
|
1538
|
-
summary: Union[SummaryContentsOptions, Literal[True]],
|
|
999
|
+
contents: Optional[Union[Dict, bool]] = None,
|
|
1539
1000
|
num_results: Optional[int] = None,
|
|
1540
1001
|
include_domains: Optional[List[str]] = None,
|
|
1541
1002
|
exclude_domains: Optional[List[str]] = None,
|
|
@@ -1545,33 +1006,102 @@ class Exa:
|
|
|
1545
1006
|
end_published_date: Optional[str] = None,
|
|
1546
1007
|
include_text: Optional[List[str]] = None,
|
|
1547
1008
|
exclude_text: Optional[List[str]] = None,
|
|
1548
|
-
use_autoprompt: Optional[bool] = None,
|
|
1549
1009
|
type: Optional[str] = None,
|
|
1550
1010
|
category: Optional[str] = None,
|
|
1551
1011
|
flags: Optional[List[str]] = None,
|
|
1552
1012
|
moderation: Optional[bool] = None,
|
|
1553
1013
|
user_location: Optional[str] = None,
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1014
|
+
) -> SearchResponse[Result]:
|
|
1015
|
+
"""Perform a search.
|
|
1016
|
+
|
|
1017
|
+
By default, returns text contents with 10,000 max characters. Use contents=False to opt-out.
|
|
1018
|
+
|
|
1019
|
+
Args:
|
|
1020
|
+
query (str): The query string.
|
|
1021
|
+
contents (dict | bool, optional): Options for retrieving page contents.
|
|
1022
|
+
Defaults to {"text": {"maxCharacters": 10000}}. Use False to disable contents.
|
|
1023
|
+
num_results (int, optional): Number of search results to return (default 10).
|
|
1024
|
+
include_domains (List[str], optional): Domains to include in the search.
|
|
1025
|
+
exclude_domains (List[str], optional): Domains to exclude from the search.
|
|
1026
|
+
start_crawl_date (str, optional): Only links crawled after this date.
|
|
1027
|
+
end_crawl_date (str, optional): Only links crawled before this date.
|
|
1028
|
+
start_published_date (str, optional): Only links published after this date.
|
|
1029
|
+
end_published_date (str, optional): Only links published before this date.
|
|
1030
|
+
include_text (List[str], optional): Strings that must appear in the page text.
|
|
1031
|
+
exclude_text (List[str], optional): Strings that must not appear in the page text.
|
|
1032
|
+
type (str, optional): 'keyword', 'neural', 'hybrid', 'fast', 'deep', or 'auto' (default 'auto').
|
|
1033
|
+
category (str, optional): e.g. 'company'
|
|
1034
|
+
flags (List[str], optional): Experimental flags for Exa usage.
|
|
1035
|
+
moderation (bool, optional): If True, the search results will be moderated for safety.
|
|
1036
|
+
user_location (str, optional): Two-letter ISO country code of the user (e.g. US).
|
|
1037
|
+
|
|
1038
|
+
Returns:
|
|
1039
|
+
SearchResponse: The response containing search results, etc.
|
|
1040
|
+
"""
|
|
1041
|
+
options = {k: v for k, v in locals().items() if k != "self" and v is not None}
|
|
1042
|
+
|
|
1043
|
+
# Handle contents parameter with default behavior
|
|
1044
|
+
if contents is False:
|
|
1045
|
+
# Explicitly no contents - remove from options
|
|
1046
|
+
options.pop("contents", None)
|
|
1047
|
+
elif contents is None and "contents" not in options:
|
|
1048
|
+
# No contents specified - add default text with 10,000 max characters
|
|
1049
|
+
options["contents"] = {"text": {"max_characters": DEFAULT_MAX_CHARACTERS}}
|
|
1050
|
+
elif contents is not None:
|
|
1051
|
+
# User provided contents - use as-is
|
|
1052
|
+
options["contents"] = contents
|
|
1053
|
+
|
|
1054
|
+
validate_search_options(options, SEARCH_OPTIONS_TYPES)
|
|
1055
|
+
options = to_camel_case(options)
|
|
1056
|
+
data = self.request("/search", options)
|
|
1057
|
+
cost_dollars = parse_cost_dollars(data.get("costDollars"))
|
|
1058
|
+
results = []
|
|
1059
|
+
for result in data["results"]:
|
|
1060
|
+
snake_result = to_snake_case(result)
|
|
1061
|
+
results.append(
|
|
1062
|
+
Result(
|
|
1063
|
+
url=snake_result.get("url"),
|
|
1064
|
+
id=snake_result.get("id"),
|
|
1065
|
+
title=snake_result.get("title"),
|
|
1066
|
+
score=snake_result.get("score"),
|
|
1067
|
+
published_date=snake_result.get("published_date"),
|
|
1068
|
+
author=snake_result.get("author"),
|
|
1069
|
+
image=snake_result.get("image"),
|
|
1070
|
+
favicon=snake_result.get("favicon"),
|
|
1071
|
+
subpages=snake_result.get("subpages"),
|
|
1072
|
+
extras=snake_result.get("extras"),
|
|
1073
|
+
text=snake_result.get("text"),
|
|
1074
|
+
summary=snake_result.get("summary"),
|
|
1075
|
+
)
|
|
1076
|
+
)
|
|
1077
|
+
return SearchResponse(
|
|
1078
|
+
results,
|
|
1079
|
+
data["resolvedSearchType"] if "resolvedSearchType" in data else None,
|
|
1080
|
+
data["autoDate"] if "autoDate" in data else None,
|
|
1081
|
+
cost_dollars=cost_dollars,
|
|
1082
|
+
)
|
|
1561
1083
|
|
|
1562
1084
|
def search_and_contents(self, query: str, **kwargs):
|
|
1085
|
+
"""
|
|
1086
|
+
DEPRECATED: Use search() instead. The search() method now returns text contents by default.
|
|
1087
|
+
|
|
1088
|
+
Migration:
|
|
1089
|
+
- search_and_contents(query) → search(query)
|
|
1090
|
+
- search_and_contents(query, text=True) → search(query, contents={"text": True})
|
|
1091
|
+
- search_and_contents(query, summary=True) → search(query, contents={"summary": True})
|
|
1092
|
+
"""
|
|
1093
|
+
|
|
1563
1094
|
options = {"query": query}
|
|
1564
1095
|
for k, v in kwargs.items():
|
|
1565
1096
|
if v is not None:
|
|
1566
1097
|
options[k] = v
|
|
1567
|
-
# If user didn't ask for any particular content, default to text
|
|
1098
|
+
# If user didn't ask for any particular content, default to text with max characters
|
|
1568
1099
|
if (
|
|
1569
1100
|
"text" not in options
|
|
1570
|
-
and "highlights" not in options
|
|
1571
1101
|
and "summary" not in options
|
|
1572
1102
|
and "extras" not in options
|
|
1573
1103
|
):
|
|
1574
|
-
options["text"] =
|
|
1104
|
+
options["text"] = {"max_characters": DEFAULT_MAX_CHARACTERS}
|
|
1575
1105
|
|
|
1576
1106
|
merged_options = {}
|
|
1577
1107
|
merged_options.update(SEARCH_OPTIONS_TYPES)
|
|
@@ -1590,7 +1120,6 @@ class Exa:
|
|
|
1590
1120
|
options,
|
|
1591
1121
|
[
|
|
1592
1122
|
"text",
|
|
1593
|
-
"highlights",
|
|
1594
1123
|
"summary",
|
|
1595
1124
|
"context",
|
|
1596
1125
|
"subpages",
|
|
@@ -1620,16 +1149,13 @@ class Exa:
|
|
|
1620
1149
|
subpages=snake_result.get("subpages"),
|
|
1621
1150
|
extras=snake_result.get("extras"),
|
|
1622
1151
|
text=snake_result.get("text"),
|
|
1623
|
-
highlights=snake_result.get("highlights"),
|
|
1624
|
-
highlight_scores=snake_result.get("highlight_scores"),
|
|
1625
1152
|
summary=snake_result.get("summary"),
|
|
1626
1153
|
)
|
|
1627
1154
|
)
|
|
1628
1155
|
return SearchResponse(
|
|
1629
1156
|
results,
|
|
1630
|
-
data
|
|
1631
|
-
data
|
|
1632
|
-
data["autoDate"] if "autoDate" in data else None,
|
|
1157
|
+
data.get("resolvedSearchType"),
|
|
1158
|
+
data.get("autoDate"),
|
|
1633
1159
|
context=data.get("context"),
|
|
1634
1160
|
cost_dollars=cost_dollars,
|
|
1635
1161
|
)
|
|
@@ -1662,37 +1188,6 @@ class Exa:
|
|
|
1662
1188
|
flags: Optional[List[str]] = None,
|
|
1663
1189
|
) -> SearchResponse[ResultWithText]: ...
|
|
1664
1190
|
|
|
1665
|
-
@overload
|
|
1666
|
-
def get_contents(
|
|
1667
|
-
self,
|
|
1668
|
-
urls: Union[str, List[str], List[_Result]],
|
|
1669
|
-
*,
|
|
1670
|
-
highlights: Union[HighlightsContentsOptions, Literal[True]],
|
|
1671
|
-
livecrawl_timeout: Optional[int] = None,
|
|
1672
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1673
|
-
filter_empty_results: Optional[bool] = None,
|
|
1674
|
-
subpages: Optional[int] = None,
|
|
1675
|
-
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1676
|
-
extras: Optional[ExtrasOptions] = None,
|
|
1677
|
-
flags: Optional[List[str]] = None,
|
|
1678
|
-
) -> SearchResponse[ResultWithHighlights]: ...
|
|
1679
|
-
|
|
1680
|
-
@overload
|
|
1681
|
-
def get_contents(
|
|
1682
|
-
self,
|
|
1683
|
-
urls: Union[str, List[str], List[_Result]],
|
|
1684
|
-
*,
|
|
1685
|
-
text: Union[TextContentsOptions, Literal[True]],
|
|
1686
|
-
highlights: Union[HighlightsContentsOptions, Literal[True]],
|
|
1687
|
-
livecrawl_timeout: Optional[int] = None,
|
|
1688
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1689
|
-
filter_empty_results: Optional[bool] = None,
|
|
1690
|
-
subpages: Optional[int] = None,
|
|
1691
|
-
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1692
|
-
extras: Optional[ExtrasOptions] = None,
|
|
1693
|
-
flags: Optional[List[str]] = None,
|
|
1694
|
-
) -> SearchResponse[ResultWithTextAndHighlights]: ...
|
|
1695
|
-
|
|
1696
1191
|
@overload
|
|
1697
1192
|
def get_contents(
|
|
1698
1193
|
self,
|
|
@@ -1724,40 +1219,14 @@ class Exa:
|
|
|
1724
1219
|
flags: Optional[List[str]] = None,
|
|
1725
1220
|
) -> SearchResponse[ResultWithTextAndSummary]: ...
|
|
1726
1221
|
|
|
1727
|
-
@overload
|
|
1728
|
-
def get_contents(
|
|
1729
|
-
self,
|
|
1730
|
-
urls: Union[str, List[str], List[_Result]],
|
|
1731
|
-
*,
|
|
1732
|
-
highlights: Union[HighlightsContentsOptions, Literal[True]],
|
|
1733
|
-
summary: Union[SummaryContentsOptions, Literal[True]],
|
|
1734
|
-
livecrawl_timeout: Optional[int] = None,
|
|
1735
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1736
|
-
filter_empty_results: Optional[bool] = None,
|
|
1737
|
-
subpages: Optional[int] = None,
|
|
1738
|
-
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1739
|
-
extras: Optional[ExtrasOptions] = None,
|
|
1740
|
-
flags: Optional[List[str]] = None,
|
|
1741
|
-
) -> SearchResponse[ResultWithHighlightsAndSummary]: ...
|
|
1742
|
-
|
|
1743
|
-
@overload
|
|
1744
|
-
def get_contents(
|
|
1745
|
-
self,
|
|
1746
|
-
urls: Union[str, List[str], List[_Result]],
|
|
1747
|
-
*,
|
|
1748
|
-
text: Union[TextContentsOptions, Literal[True]],
|
|
1749
|
-
highlights: Union[HighlightsContentsOptions, Literal[True]],
|
|
1750
|
-
summary: Union[SummaryContentsOptions, Literal[True]],
|
|
1751
|
-
livecrawl_timeout: Optional[int] = None,
|
|
1752
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1753
|
-
filter_empty_results: Optional[bool] = None,
|
|
1754
|
-
subpages: Optional[int] = None,
|
|
1755
|
-
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1756
|
-
extras: Optional[ExtrasOptions] = None,
|
|
1757
|
-
flags: Optional[List[str]] = None,
|
|
1758
|
-
) -> SearchResponse[ResultWithTextAndHighlightsAndSummary]: ...
|
|
1759
|
-
|
|
1760
1222
|
def get_contents(self, urls: Union[str, List[str], List[_Result]], **kwargs):
|
|
1223
|
+
# Normalize urls to always be a list
|
|
1224
|
+
if isinstance(urls, str):
|
|
1225
|
+
urls = [urls]
|
|
1226
|
+
elif isinstance(urls, list) and len(urls) > 0 and isinstance(urls[0], _Result):
|
|
1227
|
+
# Extract URLs from Result objects
|
|
1228
|
+
urls = [r.url for r in urls]
|
|
1229
|
+
|
|
1761
1230
|
options = {"urls": urls}
|
|
1762
1231
|
for k, v in kwargs.items():
|
|
1763
1232
|
if k != "self" and v is not None:
|
|
@@ -1765,11 +1234,10 @@ class Exa:
|
|
|
1765
1234
|
|
|
1766
1235
|
if (
|
|
1767
1236
|
"text" not in options
|
|
1768
|
-
and "highlights" not in options
|
|
1769
1237
|
and "summary" not in options
|
|
1770
1238
|
and "extras" not in options
|
|
1771
1239
|
):
|
|
1772
|
-
options["text"] =
|
|
1240
|
+
options["text"] = {"max_characters": DEFAULT_MAX_CHARACTERS}
|
|
1773
1241
|
|
|
1774
1242
|
merged_options = {}
|
|
1775
1243
|
merged_options.update(CONTENTS_OPTIONS_TYPES)
|
|
@@ -1810,14 +1278,11 @@ class Exa:
|
|
|
1810
1278
|
subpages=snake_result.get("subpages"),
|
|
1811
1279
|
extras=snake_result.get("extras"),
|
|
1812
1280
|
text=snake_result.get("text"),
|
|
1813
|
-
highlights=snake_result.get("highlights"),
|
|
1814
|
-
highlight_scores=snake_result.get("highlight_scores"),
|
|
1815
1281
|
summary=snake_result.get("summary"),
|
|
1816
1282
|
)
|
|
1817
1283
|
)
|
|
1818
1284
|
return SearchResponse(
|
|
1819
1285
|
results,
|
|
1820
|
-
data.get("autopromptString"),
|
|
1821
1286
|
data.get("resolvedSearchType"),
|
|
1822
1287
|
data.get("autoDate"),
|
|
1823
1288
|
context=data.get("context"),
|
|
@@ -1829,6 +1294,7 @@ class Exa:
|
|
|
1829
1294
|
self,
|
|
1830
1295
|
url: str,
|
|
1831
1296
|
*,
|
|
1297
|
+
contents: Optional[Union[Dict, bool]] = None,
|
|
1832
1298
|
num_results: Optional[int] = None,
|
|
1833
1299
|
include_domains: Optional[List[str]] = None,
|
|
1834
1300
|
exclude_domains: Optional[List[str]] = None,
|
|
@@ -1841,11 +1307,15 @@ class Exa:
|
|
|
1841
1307
|
exclude_source_domain: Optional[bool] = None,
|
|
1842
1308
|
category: Optional[str] = None,
|
|
1843
1309
|
flags: Optional[List[str]] = None,
|
|
1844
|
-
) -> SearchResponse[
|
|
1310
|
+
) -> SearchResponse[Result]:
|
|
1845
1311
|
"""Finds similar pages to a given URL, potentially with domain filters and date filters.
|
|
1846
1312
|
|
|
1313
|
+
By default, returns text contents with 10,000 max characters. Use contents=False to opt-out.
|
|
1314
|
+
|
|
1847
1315
|
Args:
|
|
1848
1316
|
url (str): The URL to find similar pages for.
|
|
1317
|
+
contents (dict | bool, optional): Options for retrieving page contents.
|
|
1318
|
+
Defaults to {"text": {"maxCharacters": 10000}}. Use False to disable contents.
|
|
1849
1319
|
num_results (int, optional): Number of results to return. Default is None (server default).
|
|
1850
1320
|
include_domains (List[str], optional): Domains to include in the search.
|
|
1851
1321
|
exclude_domains (List[str], optional): Domains to exclude from the search.
|
|
@@ -1860,9 +1330,21 @@ class Exa:
|
|
|
1860
1330
|
flags (List[str], optional): Experimental flags.
|
|
1861
1331
|
|
|
1862
1332
|
Returns:
|
|
1863
|
-
SearchResponse[
|
|
1333
|
+
SearchResponse[Result]
|
|
1864
1334
|
"""
|
|
1865
1335
|
options = {k: v for k, v in locals().items() if k != "self" and v is not None}
|
|
1336
|
+
|
|
1337
|
+
# Handle contents parameter with default behavior
|
|
1338
|
+
if contents is False:
|
|
1339
|
+
# Explicitly no contents - remove from options
|
|
1340
|
+
options.pop("contents", None)
|
|
1341
|
+
elif contents is None and "contents" not in options:
|
|
1342
|
+
# No contents specified - add default text with 10,000 max characters
|
|
1343
|
+
options["contents"] = {"text": {"max_characters": DEFAULT_MAX_CHARACTERS}}
|
|
1344
|
+
elif contents is not None:
|
|
1345
|
+
# User provided contents - use as-is
|
|
1346
|
+
options["contents"] = contents
|
|
1347
|
+
|
|
1866
1348
|
validate_search_options(options, FIND_SIMILAR_OPTIONS_TYPES)
|
|
1867
1349
|
options = to_camel_case(options)
|
|
1868
1350
|
data = self.request("/findSimilar", options)
|
|
@@ -1883,14 +1365,11 @@ class Exa:
|
|
|
1883
1365
|
subpages=snake_result.get("subpages"),
|
|
1884
1366
|
extras=snake_result.get("extras"),
|
|
1885
1367
|
text=snake_result.get("text"),
|
|
1886
|
-
highlights=snake_result.get("highlights"),
|
|
1887
|
-
highlight_scores=snake_result.get("highlight_scores"),
|
|
1888
1368
|
summary=snake_result.get("summary"),
|
|
1889
1369
|
)
|
|
1890
1370
|
)
|
|
1891
1371
|
return SearchResponse(
|
|
1892
1372
|
results,
|
|
1893
|
-
data.get("autopromptString"),
|
|
1894
1373
|
data.get("resolvedSearchType"),
|
|
1895
1374
|
data.get("autoDate"),
|
|
1896
1375
|
cost_dollars=cost_dollars,
|
|
@@ -1947,39 +1426,12 @@ class Exa:
|
|
|
1947
1426
|
extras: Optional[ExtrasOptions] = None,
|
|
1948
1427
|
) -> SearchResponse[ResultWithText]: ...
|
|
1949
1428
|
|
|
1950
|
-
@overload
|
|
1951
|
-
def find_similar_and_contents(
|
|
1952
|
-
self,
|
|
1953
|
-
url: str,
|
|
1954
|
-
*,
|
|
1955
|
-
highlights: Union[HighlightsContentsOptions, Literal[True]],
|
|
1956
|
-
num_results: Optional[int] = None,
|
|
1957
|
-
include_domains: Optional[List[str]] = None,
|
|
1958
|
-
exclude_domains: Optional[List[str]] = None,
|
|
1959
|
-
start_crawl_date: Optional[str] = None,
|
|
1960
|
-
end_crawl_date: Optional[str] = None,
|
|
1961
|
-
start_published_date: Optional[str] = None,
|
|
1962
|
-
end_published_date: Optional[str] = None,
|
|
1963
|
-
include_text: Optional[List[str]] = None,
|
|
1964
|
-
exclude_text: Optional[List[str]] = None,
|
|
1965
|
-
exclude_source_domain: Optional[bool] = None,
|
|
1966
|
-
category: Optional[str] = None,
|
|
1967
|
-
flags: Optional[List[str]] = None,
|
|
1968
|
-
subpages: Optional[int] = None,
|
|
1969
|
-
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1970
|
-
livecrawl_timeout: Optional[int] = None,
|
|
1971
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1972
|
-
filter_empty_results: Optional[bool] = None,
|
|
1973
|
-
extras: Optional[ExtrasOptions] = None,
|
|
1974
|
-
) -> SearchResponse[ResultWithHighlights]: ...
|
|
1975
|
-
|
|
1976
1429
|
@overload
|
|
1977
1430
|
def find_similar_and_contents(
|
|
1978
1431
|
self,
|
|
1979
1432
|
url: str,
|
|
1980
1433
|
*,
|
|
1981
1434
|
text: Union[TextContentsOptions, Literal[True]],
|
|
1982
|
-
highlights: Union[HighlightsContentsOptions, Literal[True]],
|
|
1983
1435
|
num_results: Optional[int] = None,
|
|
1984
1436
|
include_domains: Optional[List[str]] = None,
|
|
1985
1437
|
exclude_domains: Optional[List[str]] = None,
|
|
@@ -1998,7 +1450,7 @@ class Exa:
|
|
|
1998
1450
|
subpages: Optional[int] = None,
|
|
1999
1451
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
2000
1452
|
extras: Optional[ExtrasOptions] = None,
|
|
2001
|
-
) -> SearchResponse[
|
|
1453
|
+
) -> SearchResponse[ResultWithText]: ...
|
|
2002
1454
|
|
|
2003
1455
|
@overload
|
|
2004
1456
|
def find_similar_and_contents(
|
|
@@ -2053,73 +1505,23 @@ class Exa:
|
|
|
2053
1505
|
extras: Optional[ExtrasOptions] = None,
|
|
2054
1506
|
) -> SearchResponse[ResultWithTextAndSummary]: ...
|
|
2055
1507
|
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
url: str,
|
|
2060
|
-
*,
|
|
2061
|
-
highlights: Union[HighlightsContentsOptions, Literal[True]],
|
|
2062
|
-
summary: Union[SummaryContentsOptions, Literal[True]],
|
|
2063
|
-
num_results: Optional[int] = None,
|
|
2064
|
-
include_domains: Optional[List[str]] = None,
|
|
2065
|
-
exclude_domains: Optional[List[str]] = None,
|
|
2066
|
-
start_crawl_date: Optional[str] = None,
|
|
2067
|
-
end_crawl_date: Optional[str] = None,
|
|
2068
|
-
start_published_date: Optional[str] = None,
|
|
2069
|
-
end_published_date: Optional[str] = None,
|
|
2070
|
-
include_text: Optional[List[str]] = None,
|
|
2071
|
-
exclude_text: Optional[List[str]] = None,
|
|
2072
|
-
exclude_source_domain: Optional[bool] = None,
|
|
2073
|
-
category: Optional[str] = None,
|
|
2074
|
-
flags: Optional[List[str]] = None,
|
|
2075
|
-
subpages: Optional[int] = None,
|
|
2076
|
-
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
2077
|
-
livecrawl_timeout: Optional[int] = None,
|
|
2078
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
2079
|
-
filter_empty_results: Optional[bool] = None,
|
|
2080
|
-
extras: Optional[ExtrasOptions] = None,
|
|
2081
|
-
) -> SearchResponse[ResultWithHighlightsAndSummary]: ...
|
|
1508
|
+
def find_similar_and_contents(self, url: str, **kwargs):
|
|
1509
|
+
"""
|
|
1510
|
+
DEPRECATED: Use find_similar() instead. The find_similar() method now returns text contents by default.
|
|
2082
1511
|
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
url:
|
|
2087
|
-
|
|
2088
|
-
text: Union[TextContentsOptions, Literal[True]],
|
|
2089
|
-
highlights: Union[HighlightsContentsOptions, Literal[True]],
|
|
2090
|
-
summary: Union[SummaryContentsOptions, Literal[True]],
|
|
2091
|
-
num_results: Optional[int] = None,
|
|
2092
|
-
include_domains: Optional[List[str]] = None,
|
|
2093
|
-
exclude_domains: Optional[List[str]] = None,
|
|
2094
|
-
start_crawl_date: Optional[str] = None,
|
|
2095
|
-
end_crawl_date: Optional[str] = None,
|
|
2096
|
-
start_published_date: Optional[str] = None,
|
|
2097
|
-
end_published_date: Optional[str] = None,
|
|
2098
|
-
include_text: Optional[List[str]] = None,
|
|
2099
|
-
exclude_text: Optional[List[str]] = None,
|
|
2100
|
-
exclude_source_domain: Optional[bool] = None,
|
|
2101
|
-
category: Optional[str] = None,
|
|
2102
|
-
flags: Optional[List[str]] = None,
|
|
2103
|
-
livecrawl_timeout: Optional[int] = None,
|
|
2104
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
2105
|
-
filter_empty_results: Optional[bool] = None,
|
|
2106
|
-
subpages: Optional[int] = None,
|
|
2107
|
-
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
2108
|
-
extras: Optional[ExtrasOptions] = None,
|
|
2109
|
-
) -> SearchResponse[ResultWithTextAndHighlightsAndSummary]: ...
|
|
1512
|
+
Migration:
|
|
1513
|
+
- find_similar_and_contents(url) → find_similar(url)
|
|
1514
|
+
- find_similar_and_contents(url, text=True) → find_similar(url, contents={"text": True})
|
|
1515
|
+
- find_similar_and_contents(url, summary=True) → find_similar(url, contents={"summary": True})
|
|
1516
|
+
"""
|
|
2110
1517
|
|
|
2111
|
-
def find_similar_and_contents(self, url: str, **kwargs):
|
|
2112
1518
|
options = {"url": url}
|
|
2113
1519
|
for k, v in kwargs.items():
|
|
2114
1520
|
if v is not None:
|
|
2115
1521
|
options[k] = v
|
|
2116
|
-
# Default to text if none specified
|
|
2117
|
-
if
|
|
2118
|
-
"text"
|
|
2119
|
-
and "highlights" not in options
|
|
2120
|
-
and "summary" not in options
|
|
2121
|
-
):
|
|
2122
|
-
options["text"] = True
|
|
1522
|
+
# Default to text with max characters if none specified
|
|
1523
|
+
if "text" not in options and "summary" not in options:
|
|
1524
|
+
options["text"] = {"max_characters": DEFAULT_MAX_CHARACTERS}
|
|
2123
1525
|
|
|
2124
1526
|
merged_options = {}
|
|
2125
1527
|
merged_options.update(FIND_SIMILAR_OPTIONS_TYPES)
|
|
@@ -2138,7 +1540,6 @@ class Exa:
|
|
|
2138
1540
|
options,
|
|
2139
1541
|
[
|
|
2140
1542
|
"text",
|
|
2141
|
-
"highlights",
|
|
2142
1543
|
"summary",
|
|
2143
1544
|
"context",
|
|
2144
1545
|
"subpages",
|
|
@@ -2168,14 +1569,11 @@ class Exa:
|
|
|
2168
1569
|
subpages=snake_result.get("subpages"),
|
|
2169
1570
|
extras=snake_result.get("extras"),
|
|
2170
1571
|
text=snake_result.get("text"),
|
|
2171
|
-
highlights=snake_result.get("highlights"),
|
|
2172
|
-
highlight_scores=snake_result.get("highlight_scores"),
|
|
2173
1572
|
summary=snake_result.get("summary"),
|
|
2174
1573
|
)
|
|
2175
1574
|
)
|
|
2176
1575
|
return SearchResponse(
|
|
2177
1576
|
results,
|
|
2178
|
-
data.get("autopromptString"),
|
|
2179
1577
|
data.get("resolvedSearchType"),
|
|
2180
1578
|
data.get("autoDate"),
|
|
2181
1579
|
context=data.get("context"),
|
|
@@ -2205,7 +1603,6 @@ class Exa:
|
|
|
2205
1603
|
model: Union[str, ChatModel],
|
|
2206
1604
|
# Exa args
|
|
2207
1605
|
use_exa: Optional[Literal["required", "none", "auto"]] = "auto",
|
|
2208
|
-
highlights: Union[HighlightsContentsOptions, Literal[True], None] = None,
|
|
2209
1606
|
num_results: Optional[int] = 3,
|
|
2210
1607
|
include_domains: Optional[List[str]] = None,
|
|
2211
1608
|
exclude_domains: Optional[List[str]] = None,
|
|
@@ -2215,7 +1612,6 @@ class Exa:
|
|
|
2215
1612
|
end_published_date: Optional[str] = None,
|
|
2216
1613
|
include_text: Optional[List[str]] = None,
|
|
2217
1614
|
exclude_text: Optional[List[str]] = None,
|
|
2218
|
-
use_autoprompt: Optional[bool] = True,
|
|
2219
1615
|
type: Optional[str] = None,
|
|
2220
1616
|
category: Optional[str] = None,
|
|
2221
1617
|
result_max_len: int = 2048,
|
|
@@ -2227,14 +1623,12 @@ class Exa:
|
|
|
2227
1623
|
"num_results": num_results,
|
|
2228
1624
|
"include_domains": include_domains,
|
|
2229
1625
|
"exclude_domains": exclude_domains,
|
|
2230
|
-
"highlights": highlights,
|
|
2231
1626
|
"start_crawl_date": start_crawl_date,
|
|
2232
1627
|
"end_crawl_date": end_crawl_date,
|
|
2233
1628
|
"start_published_date": start_published_date,
|
|
2234
1629
|
"end_published_date": end_published_date,
|
|
2235
1630
|
"include_text": include_text,
|
|
2236
1631
|
"exclude_text": exclude_text,
|
|
2237
|
-
"use_autoprompt": use_autoprompt,
|
|
2238
1632
|
"type": type,
|
|
2239
1633
|
"category": category,
|
|
2240
1634
|
"flags": flags,
|
|
@@ -2301,14 +1695,12 @@ class Exa:
|
|
|
2301
1695
|
num_results=exa_kwargs.get("num_results"),
|
|
2302
1696
|
include_domains=exa_kwargs.get("include_domains"),
|
|
2303
1697
|
exclude_domains=exa_kwargs.get("exclude_domains"),
|
|
2304
|
-
highlights=exa_kwargs.get("highlights"),
|
|
2305
1698
|
start_crawl_date=exa_kwargs.get("start_crawl_date"),
|
|
2306
1699
|
end_crawl_date=exa_kwargs.get("end_crawl_date"),
|
|
2307
1700
|
start_published_date=exa_kwargs.get("start_published_date"),
|
|
2308
1701
|
end_published_date=exa_kwargs.get("end_published_date"),
|
|
2309
1702
|
include_text=exa_kwargs.get("include_text"),
|
|
2310
1703
|
exclude_text=exa_kwargs.get("exclude_text"),
|
|
2311
|
-
use_autoprompt=exa_kwargs.get("use_autoprompt"),
|
|
2312
1704
|
type=exa_kwargs.get("type"),
|
|
2313
1705
|
category=exa_kwargs.get("category"),
|
|
2314
1706
|
flags=exa_kwargs.get("flags"),
|
|
@@ -2512,6 +1904,7 @@ class AsyncExa(Exa):
|
|
|
2512
1904
|
self,
|
|
2513
1905
|
query: str,
|
|
2514
1906
|
*,
|
|
1907
|
+
contents: Optional[Union[Dict, bool]] = None,
|
|
2515
1908
|
num_results: Optional[int] = None,
|
|
2516
1909
|
include_domains: Optional[List[str]] = None,
|
|
2517
1910
|
exclude_domains: Optional[List[str]] = None,
|
|
@@ -2521,17 +1914,20 @@ class AsyncExa(Exa):
|
|
|
2521
1914
|
end_published_date: Optional[str] = None,
|
|
2522
1915
|
include_text: Optional[List[str]] = None,
|
|
2523
1916
|
exclude_text: Optional[List[str]] = None,
|
|
2524
|
-
use_autoprompt: Optional[bool] = None,
|
|
2525
1917
|
type: Optional[str] = None,
|
|
2526
1918
|
category: Optional[str] = None,
|
|
2527
1919
|
flags: Optional[List[str]] = None,
|
|
2528
1920
|
moderation: Optional[bool] = None,
|
|
2529
1921
|
user_location: Optional[str] = None,
|
|
2530
|
-
) -> SearchResponse[
|
|
1922
|
+
) -> SearchResponse[Result]:
|
|
2531
1923
|
"""Perform a search with a prompt-engineered query to retrieve relevant results.
|
|
2532
1924
|
|
|
1925
|
+
By default, returns text contents with 10,000 max characters. Use contents=False to opt-out.
|
|
1926
|
+
|
|
2533
1927
|
Args:
|
|
2534
1928
|
query (str): The query string.
|
|
1929
|
+
contents (dict | bool, optional): Options for retrieving page contents.
|
|
1930
|
+
Defaults to {"text": {"maxCharacters": 10000}}. Use False to disable contents.
|
|
2535
1931
|
num_results (int, optional): Number of search results to return (default 10).
|
|
2536
1932
|
include_domains (List[str], optional): Domains to include in the search.
|
|
2537
1933
|
exclude_domains (List[str], optional): Domains to exclude from the search.
|
|
@@ -2541,7 +1937,6 @@ class AsyncExa(Exa):
|
|
|
2541
1937
|
end_published_date (str, optional): Only links published before this date.
|
|
2542
1938
|
include_text (List[str], optional): Strings that must appear in the page text.
|
|
2543
1939
|
exclude_text (List[str], optional): Strings that must not appear in the page text.
|
|
2544
|
-
use_autoprompt (bool, optional): Convert query to Exa (default False).
|
|
2545
1940
|
type (str, optional): 'keyword', 'neural', 'hybrid', 'fast', 'deep', or 'auto' (default 'auto').
|
|
2546
1941
|
category (str, optional): e.g. 'company'
|
|
2547
1942
|
flags (List[str], optional): Experimental flags for Exa usage.
|
|
@@ -2552,6 +1947,18 @@ class AsyncExa(Exa):
|
|
|
2552
1947
|
SearchResponse: The response containing search results, etc.
|
|
2553
1948
|
"""
|
|
2554
1949
|
options = {k: v for k, v in locals().items() if k != "self" and v is not None}
|
|
1950
|
+
|
|
1951
|
+
# Handle contents parameter with default behavior
|
|
1952
|
+
if contents is False:
|
|
1953
|
+
# Explicitly no contents - remove from options
|
|
1954
|
+
options.pop("contents", None)
|
|
1955
|
+
elif contents is None and "contents" not in options:
|
|
1956
|
+
# No contents specified - add default text with 10,000 max characters
|
|
1957
|
+
options["contents"] = {"text": {"max_characters": DEFAULT_MAX_CHARACTERS}}
|
|
1958
|
+
elif contents is not None:
|
|
1959
|
+
# User provided contents - use as-is
|
|
1960
|
+
options["contents"] = contents
|
|
1961
|
+
|
|
2555
1962
|
validate_search_options(options, SEARCH_OPTIONS_TYPES)
|
|
2556
1963
|
options = to_camel_case(options)
|
|
2557
1964
|
data = await self.async_request("/search", options)
|
|
@@ -2572,32 +1979,37 @@ class AsyncExa(Exa):
|
|
|
2572
1979
|
subpages=snake_result.get("subpages"),
|
|
2573
1980
|
extras=snake_result.get("extras"),
|
|
2574
1981
|
text=snake_result.get("text"),
|
|
2575
|
-
highlights=snake_result.get("highlights"),
|
|
2576
|
-
highlight_scores=snake_result.get("highlight_scores"),
|
|
2577
1982
|
summary=snake_result.get("summary"),
|
|
2578
1983
|
)
|
|
2579
1984
|
)
|
|
2580
1985
|
return SearchResponse(
|
|
2581
1986
|
results,
|
|
2582
|
-
data
|
|
2583
|
-
data
|
|
2584
|
-
data["autoDate"] if "autoDate" in data else None,
|
|
1987
|
+
data.get("resolvedSearchType"),
|
|
1988
|
+
data.get("autoDate"),
|
|
2585
1989
|
cost_dollars=cost_dollars,
|
|
2586
1990
|
)
|
|
2587
1991
|
|
|
2588
1992
|
async def search_and_contents(self, query: str, **kwargs):
|
|
1993
|
+
"""
|
|
1994
|
+
DEPRECATED: Use search() instead. The search() method now returns text contents by default.
|
|
1995
|
+
|
|
1996
|
+
Migration:
|
|
1997
|
+
- search_and_contents(query) → search(query)
|
|
1998
|
+
- search_and_contents(query, text=True) → search(query, contents={"text": True})
|
|
1999
|
+
- search_and_contents(query, summary=True) → search(query, contents={"summary": True})
|
|
2000
|
+
"""
|
|
2001
|
+
|
|
2589
2002
|
options = {"query": query}
|
|
2590
2003
|
for k, v in kwargs.items():
|
|
2591
2004
|
if v is not None:
|
|
2592
2005
|
options[k] = v
|
|
2593
|
-
# If user didn't ask for any particular content, default to text
|
|
2006
|
+
# If user didn't ask for any particular content, default to text with max characters
|
|
2594
2007
|
if (
|
|
2595
2008
|
"text" not in options
|
|
2596
|
-
and "highlights" not in options
|
|
2597
2009
|
and "summary" not in options
|
|
2598
2010
|
and "extras" not in options
|
|
2599
2011
|
):
|
|
2600
|
-
options["text"] =
|
|
2012
|
+
options["text"] = {"max_characters": DEFAULT_MAX_CHARACTERS}
|
|
2601
2013
|
|
|
2602
2014
|
merged_options = {}
|
|
2603
2015
|
merged_options.update(SEARCH_OPTIONS_TYPES)
|
|
@@ -2616,7 +2028,6 @@ class AsyncExa(Exa):
|
|
|
2616
2028
|
options,
|
|
2617
2029
|
[
|
|
2618
2030
|
"text",
|
|
2619
|
-
"highlights",
|
|
2620
2031
|
"summary",
|
|
2621
2032
|
"context",
|
|
2622
2033
|
"subpages",
|
|
@@ -2646,21 +2057,25 @@ class AsyncExa(Exa):
|
|
|
2646
2057
|
subpages=snake_result.get("subpages"),
|
|
2647
2058
|
extras=snake_result.get("extras"),
|
|
2648
2059
|
text=snake_result.get("text"),
|
|
2649
|
-
highlights=snake_result.get("highlights"),
|
|
2650
|
-
highlight_scores=snake_result.get("highlight_scores"),
|
|
2651
2060
|
summary=snake_result.get("summary"),
|
|
2652
2061
|
)
|
|
2653
2062
|
)
|
|
2654
2063
|
return SearchResponse(
|
|
2655
2064
|
results,
|
|
2656
|
-
data
|
|
2657
|
-
data
|
|
2658
|
-
data["autoDate"] if "autoDate" in data else None,
|
|
2065
|
+
data.get("resolvedSearchType"),
|
|
2066
|
+
data.get("autoDate"),
|
|
2659
2067
|
context=data.get("context"),
|
|
2660
2068
|
cost_dollars=cost_dollars,
|
|
2661
2069
|
)
|
|
2662
2070
|
|
|
2663
2071
|
async def get_contents(self, urls: Union[str, List[str], List[_Result]], **kwargs):
|
|
2072
|
+
# Normalize urls to always be a list
|
|
2073
|
+
if isinstance(urls, str):
|
|
2074
|
+
urls = [urls]
|
|
2075
|
+
elif isinstance(urls, list) and len(urls) > 0 and isinstance(urls[0], _Result):
|
|
2076
|
+
# Extract URLs from Result objects
|
|
2077
|
+
urls = [r.url for r in urls]
|
|
2078
|
+
|
|
2664
2079
|
options = {"urls": urls}
|
|
2665
2080
|
for k, v in kwargs.items():
|
|
2666
2081
|
if k != "self" and v is not None:
|
|
@@ -2668,11 +2083,10 @@ class AsyncExa(Exa):
|
|
|
2668
2083
|
|
|
2669
2084
|
if (
|
|
2670
2085
|
"text" not in options
|
|
2671
|
-
and "highlights" not in options
|
|
2672
2086
|
and "summary" not in options
|
|
2673
2087
|
and "extras" not in options
|
|
2674
2088
|
):
|
|
2675
|
-
options["text"] =
|
|
2089
|
+
options["text"] = {"max_characters": DEFAULT_MAX_CHARACTERS}
|
|
2676
2090
|
|
|
2677
2091
|
merged_options = {}
|
|
2678
2092
|
merged_options.update(CONTENTS_OPTIONS_TYPES)
|
|
@@ -2713,14 +2127,11 @@ class AsyncExa(Exa):
|
|
|
2713
2127
|
subpages=snake_result.get("subpages"),
|
|
2714
2128
|
extras=snake_result.get("extras"),
|
|
2715
2129
|
text=snake_result.get("text"),
|
|
2716
|
-
highlights=snake_result.get("highlights"),
|
|
2717
|
-
highlight_scores=snake_result.get("highlight_scores"),
|
|
2718
2130
|
summary=snake_result.get("summary"),
|
|
2719
2131
|
)
|
|
2720
2132
|
)
|
|
2721
2133
|
return SearchResponse(
|
|
2722
2134
|
results,
|
|
2723
|
-
data.get("autopromptString"),
|
|
2724
2135
|
data.get("resolvedSearchType"),
|
|
2725
2136
|
data.get("autoDate"),
|
|
2726
2137
|
context=data.get("context"),
|
|
@@ -2732,6 +2143,7 @@ class AsyncExa(Exa):
|
|
|
2732
2143
|
self,
|
|
2733
2144
|
url: str,
|
|
2734
2145
|
*,
|
|
2146
|
+
contents: Optional[Union[Dict, bool]] = None,
|
|
2735
2147
|
num_results: Optional[int] = None,
|
|
2736
2148
|
include_domains: Optional[List[str]] = None,
|
|
2737
2149
|
exclude_domains: Optional[List[str]] = None,
|
|
@@ -2744,11 +2156,15 @@ class AsyncExa(Exa):
|
|
|
2744
2156
|
exclude_source_domain: Optional[bool] = None,
|
|
2745
2157
|
category: Optional[str] = None,
|
|
2746
2158
|
flags: Optional[List[str]] = None,
|
|
2747
|
-
) -> SearchResponse[
|
|
2159
|
+
) -> SearchResponse[Result]:
|
|
2748
2160
|
"""Finds similar pages to a given URL, potentially with domain filters and date filters.
|
|
2749
2161
|
|
|
2162
|
+
By default, returns text contents with 10,000 max characters. Use contents=False to opt-out.
|
|
2163
|
+
|
|
2750
2164
|
Args:
|
|
2751
2165
|
url (str): The URL to find similar pages for.
|
|
2166
|
+
contents (dict | bool, optional): Options for retrieving page contents.
|
|
2167
|
+
Defaults to {"text": {"maxCharacters": 10000}}. Use False to disable contents.
|
|
2752
2168
|
num_results (int, optional): Number of results to return. Default is None (server default).
|
|
2753
2169
|
include_domains (List[str], optional): Domains to include in the search.
|
|
2754
2170
|
exclude_domains (List[str], optional): Domains to exclude from the search.
|
|
@@ -2763,9 +2179,21 @@ class AsyncExa(Exa):
|
|
|
2763
2179
|
flags (List[str], optional): Experimental flags.
|
|
2764
2180
|
|
|
2765
2181
|
Returns:
|
|
2766
|
-
SearchResponse[
|
|
2182
|
+
SearchResponse[Result]
|
|
2767
2183
|
"""
|
|
2768
2184
|
options = {k: v for k, v in locals().items() if k != "self" and v is not None}
|
|
2185
|
+
|
|
2186
|
+
# Handle contents parameter with default behavior
|
|
2187
|
+
if contents is False:
|
|
2188
|
+
# Explicitly no contents - remove from options
|
|
2189
|
+
options.pop("contents", None)
|
|
2190
|
+
elif contents is None and "contents" not in options:
|
|
2191
|
+
# No contents specified - add default text with 10,000 max characters
|
|
2192
|
+
options["contents"] = {"text": {"max_characters": DEFAULT_MAX_CHARACTERS}}
|
|
2193
|
+
elif contents is not None:
|
|
2194
|
+
# User provided contents - use as-is
|
|
2195
|
+
options["contents"] = contents
|
|
2196
|
+
|
|
2769
2197
|
validate_search_options(options, FIND_SIMILAR_OPTIONS_TYPES)
|
|
2770
2198
|
options = to_camel_case(options)
|
|
2771
2199
|
data = await self.async_request("/findSimilar", options)
|
|
@@ -2786,31 +2214,32 @@ class AsyncExa(Exa):
|
|
|
2786
2214
|
subpages=snake_result.get("subpages"),
|
|
2787
2215
|
extras=snake_result.get("extras"),
|
|
2788
2216
|
text=snake_result.get("text"),
|
|
2789
|
-
highlights=snake_result.get("highlights"),
|
|
2790
|
-
highlight_scores=snake_result.get("highlight_scores"),
|
|
2791
2217
|
summary=snake_result.get("summary"),
|
|
2792
2218
|
)
|
|
2793
2219
|
)
|
|
2794
2220
|
return SearchResponse(
|
|
2795
2221
|
results,
|
|
2796
|
-
data.get("autopromptString"),
|
|
2797
2222
|
data.get("resolvedSearchType"),
|
|
2798
2223
|
data.get("autoDate"),
|
|
2799
2224
|
cost_dollars=cost_dollars,
|
|
2800
2225
|
)
|
|
2801
2226
|
|
|
2802
2227
|
async def find_similar_and_contents(self, url: str, **kwargs):
|
|
2228
|
+
"""
|
|
2229
|
+
DEPRECATED: Use find_similar() instead. The find_similar() method now returns text contents by default.
|
|
2230
|
+
|
|
2231
|
+
Migration:
|
|
2232
|
+
- find_similar_and_contents(url) → find_similar(url)
|
|
2233
|
+
- find_similar_and_contents(url, text=True) → find_similar(url, contents={"text": True})
|
|
2234
|
+
- find_similar_and_contents(url, summary=True) → find_similar(url, contents={"summary": True})
|
|
2235
|
+
"""
|
|
2803
2236
|
options = {"url": url}
|
|
2804
2237
|
for k, v in kwargs.items():
|
|
2805
2238
|
if v is not None:
|
|
2806
2239
|
options[k] = v
|
|
2807
|
-
# Default to text if none specified
|
|
2808
|
-
if
|
|
2809
|
-
"text"
|
|
2810
|
-
and "highlights" not in options
|
|
2811
|
-
and "summary" not in options
|
|
2812
|
-
):
|
|
2813
|
-
options["text"] = True
|
|
2240
|
+
# Default to text with max characters if none specified
|
|
2241
|
+
if "text" not in options and "summary" not in options:
|
|
2242
|
+
options["text"] = {"max_characters": DEFAULT_MAX_CHARACTERS}
|
|
2814
2243
|
|
|
2815
2244
|
merged_options = {}
|
|
2816
2245
|
merged_options.update(FIND_SIMILAR_OPTIONS_TYPES)
|
|
@@ -2829,7 +2258,6 @@ class AsyncExa(Exa):
|
|
|
2829
2258
|
options,
|
|
2830
2259
|
[
|
|
2831
2260
|
"text",
|
|
2832
|
-
"highlights",
|
|
2833
2261
|
"summary",
|
|
2834
2262
|
"context",
|
|
2835
2263
|
"subpages",
|
|
@@ -2859,14 +2287,11 @@ class AsyncExa(Exa):
|
|
|
2859
2287
|
subpages=snake_result.get("subpages"),
|
|
2860
2288
|
extras=snake_result.get("extras"),
|
|
2861
2289
|
text=snake_result.get("text"),
|
|
2862
|
-
highlights=snake_result.get("highlights"),
|
|
2863
|
-
highlight_scores=snake_result.get("highlight_scores"),
|
|
2864
2290
|
summary=snake_result.get("summary"),
|
|
2865
2291
|
)
|
|
2866
2292
|
)
|
|
2867
2293
|
return SearchResponse(
|
|
2868
2294
|
results,
|
|
2869
|
-
data.get("autopromptString"),
|
|
2870
2295
|
data.get("resolvedSearchType"),
|
|
2871
2296
|
data.get("autoDate"),
|
|
2872
2297
|
context=data.get("context"),
|