exa-py 1.7.3__py3-none-any.whl → 1.8.4__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
CHANGED
|
@@ -30,6 +30,7 @@ from exa_py.utils import (
|
|
|
30
30
|
maybe_get_query,
|
|
31
31
|
)
|
|
32
32
|
import os
|
|
33
|
+
from typing import Iterator
|
|
33
34
|
|
|
34
35
|
is_beta = os.getenv("IS_BETA") == "True"
|
|
35
36
|
|
|
@@ -57,11 +58,13 @@ def to_camel_case(data: dict) -> dict:
|
|
|
57
58
|
Returns:
|
|
58
59
|
dict: The dictionary with keys converted to camelCase format.
|
|
59
60
|
"""
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
if isinstance(data, dict):
|
|
62
|
+
return {
|
|
63
|
+
snake_to_camel(k): to_camel_case(v) if isinstance(v, dict) else v
|
|
64
|
+
for k, v in data.items()
|
|
65
|
+
if v is not None
|
|
66
|
+
}
|
|
67
|
+
return data
|
|
65
68
|
|
|
66
69
|
|
|
67
70
|
def camel_to_snake(camel_str: str) -> str:
|
|
@@ -87,10 +90,12 @@ def to_snake_case(data: dict) -> dict:
|
|
|
87
90
|
Returns:
|
|
88
91
|
dict: The dictionary with keys converted to snake_case format.
|
|
89
92
|
"""
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
if isinstance(data, dict):
|
|
94
|
+
return {
|
|
95
|
+
camel_to_snake(k): to_snake_case(v) if isinstance(v, dict) else v
|
|
96
|
+
for k, v in data.items()
|
|
97
|
+
}
|
|
98
|
+
return data
|
|
94
99
|
|
|
95
100
|
|
|
96
101
|
SEARCH_OPTIONS_TYPES = {
|
|
@@ -105,9 +110,10 @@ SEARCH_OPTIONS_TYPES = {
|
|
|
105
110
|
"include_text": [list], # Must be present in webpage text. (One string, up to 5 words)
|
|
106
111
|
"exclude_text": [list], # Must not be present in webpage text. (One string, up to 5 words)
|
|
107
112
|
"use_autoprompt": [bool], # Convert query to Exa. (Default: false)
|
|
108
|
-
"type": [str], # 'keyword', 'neural', or 'auto' (Default: auto)
|
|
113
|
+
"type": [str], # 'keyword', 'neural', or 'auto' (Default: auto)
|
|
109
114
|
"category": [str], # A data category to focus on: 'company', 'research paper', 'news', 'pdf', 'github', 'tweet', 'personal site', 'linkedin profile', 'financial report'
|
|
110
|
-
"flags": [list],
|
|
115
|
+
"flags": [list], # Experimental flags array for Exa usage.
|
|
116
|
+
"moderation": [bool], # If true, moderate search results for safety.
|
|
111
117
|
}
|
|
112
118
|
|
|
113
119
|
FIND_SIMILAR_OPTIONS_TYPES = {
|
|
@@ -123,7 +129,7 @@ FIND_SIMILAR_OPTIONS_TYPES = {
|
|
|
123
129
|
"exclude_text": [list],
|
|
124
130
|
"exclude_source_domain": [bool],
|
|
125
131
|
"category": [str],
|
|
126
|
-
"flags": [list],
|
|
132
|
+
"flags": [list], # Experimental flags array for Exa usage.
|
|
127
133
|
}
|
|
128
134
|
|
|
129
135
|
# the livecrawl options
|
|
@@ -197,7 +203,7 @@ class HighlightsContentsOptions(TypedDict, total=False):
|
|
|
197
203
|
"""A class representing the options that you can specify when requesting highlights
|
|
198
204
|
|
|
199
205
|
Attributes:
|
|
200
|
-
query (str): The query string for the highlights.
|
|
206
|
+
query (str): The query string for the highlights.
|
|
201
207
|
num_sentences (int): Size of highlights to return, in sentences. Default: 5
|
|
202
208
|
highlights_per_url (int): Number of highlights to return per URL. Default: 1
|
|
203
209
|
"""
|
|
@@ -216,6 +222,7 @@ class SummaryContentsOptions(TypedDict, total=False):
|
|
|
216
222
|
|
|
217
223
|
query: str
|
|
218
224
|
|
|
225
|
+
|
|
219
226
|
class ExtrasOptions(TypedDict, total=False):
|
|
220
227
|
"""A class representing additional extraction fields (e.g. links, images)"""
|
|
221
228
|
|
|
@@ -495,6 +502,59 @@ class ResultWithTextAndHighlightsAndSummary(_Result):
|
|
|
495
502
|
)
|
|
496
503
|
|
|
497
504
|
|
|
505
|
+
@dataclass
|
|
506
|
+
class AnswerResult:
|
|
507
|
+
"""A class representing a source result for an answer.
|
|
508
|
+
|
|
509
|
+
Attributes:
|
|
510
|
+
title (str): The title of the search result.
|
|
511
|
+
url (str): The URL of the search result.
|
|
512
|
+
id (str): The temporary ID for the document.
|
|
513
|
+
published_date (str, optional): An estimate of the creation date, from parsing HTML content.
|
|
514
|
+
author (str, optional): If available, the author of the content.
|
|
515
|
+
"""
|
|
516
|
+
|
|
517
|
+
url: str
|
|
518
|
+
id: str
|
|
519
|
+
title: Optional[str] = None
|
|
520
|
+
published_date: Optional[str] = None
|
|
521
|
+
author: Optional[str] = None
|
|
522
|
+
|
|
523
|
+
def __init__(self, **kwargs):
|
|
524
|
+
self.url = kwargs["url"]
|
|
525
|
+
self.id = kwargs["id"]
|
|
526
|
+
self.title = kwargs.get("title")
|
|
527
|
+
self.published_date = kwargs.get("published_date")
|
|
528
|
+
self.author = kwargs.get("author")
|
|
529
|
+
|
|
530
|
+
def __str__(self):
|
|
531
|
+
return (
|
|
532
|
+
f"Title: {self.title}\n"
|
|
533
|
+
f"URL: {self.url}\n"
|
|
534
|
+
f"ID: {self.id}\n"
|
|
535
|
+
f"Published Date: {self.published_date}\n"
|
|
536
|
+
f"Author: {self.author}\n"
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
@dataclass
|
|
541
|
+
class AnswerResponse:
|
|
542
|
+
"""A class representing the response for an answer operation.
|
|
543
|
+
|
|
544
|
+
Attributes:
|
|
545
|
+
answer (str): The generated answer.
|
|
546
|
+
sources (List[AnswerResult]): A list of sources used to generate the answer.
|
|
547
|
+
"""
|
|
548
|
+
|
|
549
|
+
answer: str
|
|
550
|
+
sources: List[AnswerResult]
|
|
551
|
+
|
|
552
|
+
def __str__(self):
|
|
553
|
+
output = f"Answer: {self.answer}\n\nSources:\n"
|
|
554
|
+
output += "\n\n".join(str(source) for source in self.sources)
|
|
555
|
+
return output
|
|
556
|
+
|
|
557
|
+
|
|
498
558
|
T = TypeVar("T")
|
|
499
559
|
|
|
500
560
|
|
|
@@ -548,7 +608,7 @@ class Exa:
|
|
|
548
608
|
self,
|
|
549
609
|
api_key: Optional[str],
|
|
550
610
|
base_url: str = "https://api.exa.ai",
|
|
551
|
-
user_agent: str = "exa-py 1.
|
|
611
|
+
user_agent: str = "exa-py 1.8.4",
|
|
552
612
|
):
|
|
553
613
|
"""Initialize the Exa client with the provided API key and optional base URL and user agent.
|
|
554
614
|
|
|
@@ -568,11 +628,28 @@ class Exa:
|
|
|
568
628
|
self.headers = {"x-api-key": api_key, "User-Agent": user_agent}
|
|
569
629
|
|
|
570
630
|
def request(self, endpoint: str, data):
|
|
631
|
+
"""Send a POST request to the Exa API, optionally streaming if data['stream'] is True.
|
|
632
|
+
|
|
633
|
+
Args:
|
|
634
|
+
endpoint (str): The API endpoint (path).
|
|
635
|
+
data (dict): The JSON payload to send.
|
|
636
|
+
|
|
637
|
+
Returns:
|
|
638
|
+
Union[dict, Iterator[str]]: If streaming, returns an iterator of strings (line-by-line).
|
|
639
|
+
Otherwise, returns the JSON-decoded response as a dict.
|
|
640
|
+
|
|
641
|
+
Raises:
|
|
642
|
+
ValueError: If the request fails (non-200 status code).
|
|
643
|
+
"""
|
|
644
|
+
if data.get("stream"):
|
|
645
|
+
res = requests.post(self.base_url + endpoint, json=data, headers=self.headers, stream=True)
|
|
646
|
+
if res.status_code != 200:
|
|
647
|
+
raise ValueError(f"Request failed with status code {res.status_code}: {res.text}")
|
|
648
|
+
return (line.decode("utf-8") for line in res.iter_lines() if line)
|
|
649
|
+
|
|
571
650
|
res = requests.post(self.base_url + endpoint, json=data, headers=self.headers)
|
|
572
651
|
if res.status_code != 200:
|
|
573
|
-
raise ValueError(
|
|
574
|
-
f"Request failed with status code {res.status_code}: {res.text}"
|
|
575
|
-
)
|
|
652
|
+
raise ValueError(f"Request failed with status code {res.status_code}: {res.text}")
|
|
576
653
|
return res.json()
|
|
577
654
|
|
|
578
655
|
def search(
|
|
@@ -592,6 +669,7 @@ class Exa:
|
|
|
592
669
|
type: Optional[str] = None,
|
|
593
670
|
category: Optional[str] = None,
|
|
594
671
|
flags: Optional[List[str]] = None,
|
|
672
|
+
moderation: Optional[bool] = None,
|
|
595
673
|
) -> SearchResponse[_Result]:
|
|
596
674
|
"""Perform a search with a prompt-engineered query to retrieve relevant results.
|
|
597
675
|
|
|
@@ -610,6 +688,7 @@ class Exa:
|
|
|
610
688
|
type (str, optional): 'keyword' or 'neural' (default 'neural').
|
|
611
689
|
category (str, optional): e.g. 'company'
|
|
612
690
|
flags (List[str], optional): Experimental flags for Exa usage.
|
|
691
|
+
moderation (bool, optional): If True, the search results will be moderated for safety.
|
|
613
692
|
|
|
614
693
|
Returns:
|
|
615
694
|
SearchResponse: The response containing search results, etc.
|
|
@@ -642,12 +721,13 @@ class Exa:
|
|
|
642
721
|
use_autoprompt: Optional[bool] = None,
|
|
643
722
|
type: Optional[str] = None,
|
|
644
723
|
category: Optional[str] = None,
|
|
724
|
+
flags: Optional[List[str]] = None,
|
|
725
|
+
moderation: Optional[bool] = None,
|
|
645
726
|
livecrawl_timeout: Optional[int] = None,
|
|
646
727
|
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
647
728
|
filter_empty_results: Optional[bool] = None,
|
|
648
729
|
subpages: Optional[int] = None,
|
|
649
730
|
extras: Optional[ExtrasOptions] = None,
|
|
650
|
-
flags: Optional[List[str]] = None,
|
|
651
731
|
) -> SearchResponse[ResultWithText]:
|
|
652
732
|
...
|
|
653
733
|
|
|
@@ -669,12 +749,13 @@ class Exa:
|
|
|
669
749
|
use_autoprompt: Optional[bool] = None,
|
|
670
750
|
type: Optional[str] = None,
|
|
671
751
|
category: Optional[str] = None,
|
|
752
|
+
flags: Optional[List[str]] = None,
|
|
753
|
+
moderation: Optional[bool] = None,
|
|
672
754
|
subpages: Optional[int] = None,
|
|
673
755
|
livecrawl_timeout: Optional[int] = None,
|
|
674
756
|
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
675
757
|
filter_empty_results: Optional[bool] = None,
|
|
676
758
|
extras: Optional[ExtrasOptions] = None,
|
|
677
|
-
flags: Optional[List[str]] = None,
|
|
678
759
|
) -> SearchResponse[ResultWithText]:
|
|
679
760
|
...
|
|
680
761
|
|
|
@@ -698,11 +779,12 @@ class Exa:
|
|
|
698
779
|
category: Optional[str] = None,
|
|
699
780
|
subpages: Optional[int] = None,
|
|
700
781
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
782
|
+
flags: Optional[List[str]] = None,
|
|
783
|
+
moderation: Optional[bool] = None,
|
|
701
784
|
livecrawl_timeout: Optional[int] = None,
|
|
702
785
|
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
703
786
|
filter_empty_results: Optional[bool] = None,
|
|
704
787
|
extras: Optional[ExtrasOptions] = None,
|
|
705
|
-
flags: Optional[List[str]] = None,
|
|
706
788
|
) -> SearchResponse[ResultWithHighlights]:
|
|
707
789
|
...
|
|
708
790
|
|
|
@@ -725,13 +807,14 @@ class Exa:
|
|
|
725
807
|
use_autoprompt: Optional[bool] = None,
|
|
726
808
|
type: Optional[str] = None,
|
|
727
809
|
category: Optional[str] = None,
|
|
728
|
-
livecrawl_timeout: Optional[int] = None,
|
|
729
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
730
810
|
subpages: Optional[int] = None,
|
|
731
811
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
812
|
+
flags: Optional[List[str]] = None,
|
|
813
|
+
moderation: Optional[bool] = None,
|
|
814
|
+
livecrawl_timeout: Optional[int] = None,
|
|
815
|
+
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
732
816
|
filter_empty_results: Optional[bool] = None,
|
|
733
817
|
extras: Optional[ExtrasOptions] = None,
|
|
734
|
-
flags: Optional[List[str]] = None,
|
|
735
818
|
) -> SearchResponse[ResultWithTextAndHighlights]:
|
|
736
819
|
...
|
|
737
820
|
|
|
@@ -755,11 +838,12 @@ class Exa:
|
|
|
755
838
|
category: Optional[str] = None,
|
|
756
839
|
subpages: Optional[int] = None,
|
|
757
840
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
841
|
+
flags: Optional[List[str]] = None,
|
|
842
|
+
moderation: Optional[bool] = None,
|
|
758
843
|
livecrawl_timeout: Optional[int] = None,
|
|
759
844
|
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
760
845
|
filter_empty_results: Optional[bool] = None,
|
|
761
846
|
extras: Optional[ExtrasOptions] = None,
|
|
762
|
-
flags: Optional[List[str]] = None,
|
|
763
847
|
) -> SearchResponse[ResultWithSummary]:
|
|
764
848
|
...
|
|
765
849
|
|
|
@@ -784,11 +868,12 @@ class Exa:
|
|
|
784
868
|
category: Optional[str] = None,
|
|
785
869
|
subpages: Optional[int] = None,
|
|
786
870
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
871
|
+
flags: Optional[List[str]] = None,
|
|
872
|
+
moderation: Optional[bool] = None,
|
|
787
873
|
livecrawl_timeout: Optional[int] = None,
|
|
788
874
|
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
789
875
|
filter_empty_results: Optional[bool] = None,
|
|
790
876
|
extras: Optional[ExtrasOptions] = None,
|
|
791
|
-
flags: Optional[List[str]] = None,
|
|
792
877
|
) -> SearchResponse[ResultWithTextAndSummary]:
|
|
793
878
|
...
|
|
794
879
|
|
|
@@ -813,11 +898,12 @@ class Exa:
|
|
|
813
898
|
category: Optional[str] = None,
|
|
814
899
|
subpages: Optional[int] = None,
|
|
815
900
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
901
|
+
flags: Optional[List[str]] = None,
|
|
902
|
+
moderation: Optional[bool] = None,
|
|
816
903
|
livecrawl_timeout: Optional[int] = None,
|
|
817
904
|
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
818
905
|
filter_empty_results: Optional[bool] = None,
|
|
819
906
|
extras: Optional[ExtrasOptions] = None,
|
|
820
|
-
flags: Optional[List[str]] = None,
|
|
821
907
|
) -> SearchResponse[ResultWithHighlightsAndSummary]:
|
|
822
908
|
...
|
|
823
909
|
|
|
@@ -841,13 +927,14 @@ class Exa:
|
|
|
841
927
|
use_autoprompt: Optional[bool] = None,
|
|
842
928
|
type: Optional[str] = None,
|
|
843
929
|
category: Optional[str] = None,
|
|
930
|
+
flags: Optional[List[str]] = None,
|
|
931
|
+
moderation: Optional[bool] = None,
|
|
844
932
|
livecrawl_timeout: Optional[int] = None,
|
|
845
933
|
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
846
934
|
subpages: Optional[int] = None,
|
|
847
935
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
848
936
|
filter_empty_results: Optional[bool] = None,
|
|
849
937
|
extras: Optional[ExtrasOptions] = None,
|
|
850
|
-
flags: Optional[List[str]] = None,
|
|
851
938
|
) -> SearchResponse[ResultWithTextAndHighlightsAndSummary]:
|
|
852
939
|
...
|
|
853
940
|
|
|
@@ -864,7 +951,11 @@ class Exa:
|
|
|
864
951
|
|
|
865
952
|
validate_search_options(
|
|
866
953
|
options,
|
|
867
|
-
{
|
|
954
|
+
{
|
|
955
|
+
**SEARCH_OPTIONS_TYPES,
|
|
956
|
+
**CONTENTS_OPTIONS_TYPES,
|
|
957
|
+
**CONTENTS_ENDPOINT_OPTIONS_TYPES,
|
|
958
|
+
},
|
|
868
959
|
)
|
|
869
960
|
|
|
870
961
|
# Nest the appropriate fields under "contents"
|
|
@@ -1021,13 +1112,19 @@ class Exa:
|
|
|
1021
1112
|
flags: Optional[List[str]] = None,
|
|
1022
1113
|
) -> SearchResponse[ResultWithTextAndHighlightsAndSummary]:
|
|
1023
1114
|
...
|
|
1115
|
+
|
|
1024
1116
|
def get_contents(self, urls: Union[str, List[str], List[_Result]], **kwargs):
|
|
1025
1117
|
options = {
|
|
1026
1118
|
k: v
|
|
1027
1119
|
for k, v in {"urls": urls, **kwargs}.items()
|
|
1028
1120
|
if k != "self" and v is not None
|
|
1029
1121
|
}
|
|
1030
|
-
if
|
|
1122
|
+
if (
|
|
1123
|
+
"text" not in options
|
|
1124
|
+
and "highlights" not in options
|
|
1125
|
+
and "summary" not in options
|
|
1126
|
+
and "extras" not in options
|
|
1127
|
+
):
|
|
1031
1128
|
options["text"] = True
|
|
1032
1129
|
|
|
1033
1130
|
validate_search_options(
|
|
@@ -1038,9 +1135,9 @@ class Exa:
|
|
|
1038
1135
|
data = self.request("/contents", options)
|
|
1039
1136
|
return SearchResponse(
|
|
1040
1137
|
[Result(**to_snake_case(result)) for result in data["results"]],
|
|
1041
|
-
data
|
|
1042
|
-
data
|
|
1043
|
-
data
|
|
1138
|
+
data.get("autopromptString"),
|
|
1139
|
+
data.get("resolvedSearchType"),
|
|
1140
|
+
data.get("autoDate"),
|
|
1044
1141
|
)
|
|
1045
1142
|
|
|
1046
1143
|
def find_similar(
|
|
@@ -1060,15 +1157,35 @@ class Exa:
|
|
|
1060
1157
|
category: Optional[str] = None,
|
|
1061
1158
|
flags: Optional[List[str]] = None,
|
|
1062
1159
|
) -> SearchResponse[_Result]:
|
|
1160
|
+
"""Finds similar pages to a given URL, potentially with domain filters and date filters.
|
|
1161
|
+
|
|
1162
|
+
Args:
|
|
1163
|
+
url (str): The URL to find similar pages for.
|
|
1164
|
+
num_results (int, optional): Number of results to return. Default is None (server default).
|
|
1165
|
+
include_domains (List[str], optional): Domains to include in the search.
|
|
1166
|
+
exclude_domains (List[str], optional): Domains to exclude from the search.
|
|
1167
|
+
start_crawl_date (str, optional): Only links crawled after this date.
|
|
1168
|
+
end_crawl_date (str, optional): Only links crawled before this date.
|
|
1169
|
+
start_published_date (str, optional): Only links published after this date.
|
|
1170
|
+
end_published_date (str, optional): Only links published before this date.
|
|
1171
|
+
include_text (List[str], optional): Strings that must appear in the page text.
|
|
1172
|
+
exclude_text (List[str], optional): Strings that must not appear in the page text.
|
|
1173
|
+
exclude_source_domain (bool, optional): Whether to exclude the source domain.
|
|
1174
|
+
category (str, optional): A data category to focus on.
|
|
1175
|
+
flags (List[str], optional): Experimental flags.
|
|
1176
|
+
|
|
1177
|
+
Returns:
|
|
1178
|
+
SearchResponse[_Result]
|
|
1179
|
+
"""
|
|
1063
1180
|
options = {k: v for k, v in locals().items() if k != "self" and v is not None}
|
|
1064
1181
|
validate_search_options(options, FIND_SIMILAR_OPTIONS_TYPES)
|
|
1065
1182
|
options = to_camel_case(options)
|
|
1066
1183
|
data = self.request("/findSimilar", options)
|
|
1067
1184
|
return SearchResponse(
|
|
1068
1185
|
[Result(**to_snake_case(result)) for result in data["results"]],
|
|
1069
|
-
data
|
|
1070
|
-
data
|
|
1071
|
-
data
|
|
1186
|
+
data.get("autopromptString"),
|
|
1187
|
+
data.get("resolvedSearchType"),
|
|
1188
|
+
data.get("autoDate"),
|
|
1072
1189
|
)
|
|
1073
1190
|
|
|
1074
1191
|
@overload
|
|
@@ -1087,13 +1204,13 @@ class Exa:
|
|
|
1087
1204
|
exclude_text: Optional[List[str]] = None,
|
|
1088
1205
|
exclude_source_domain: Optional[bool] = None,
|
|
1089
1206
|
category: Optional[str] = None,
|
|
1207
|
+
flags: Optional[List[str]] = None,
|
|
1090
1208
|
livecrawl_timeout: Optional[int] = None,
|
|
1091
1209
|
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1210
|
+
filter_empty_results: Optional[bool] = None,
|
|
1092
1211
|
subpages: Optional[int] = None,
|
|
1093
1212
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1094
|
-
filter_empty_results: Optional[bool] = None,
|
|
1095
1213
|
extras: Optional[ExtrasOptions] = None,
|
|
1096
|
-
flags: Optional[List[str]] = None,
|
|
1097
1214
|
) -> SearchResponse[ResultWithText]:
|
|
1098
1215
|
...
|
|
1099
1216
|
|
|
@@ -1114,13 +1231,13 @@ class Exa:
|
|
|
1114
1231
|
exclude_text: Optional[List[str]] = None,
|
|
1115
1232
|
exclude_source_domain: Optional[bool] = None,
|
|
1116
1233
|
category: Optional[str] = None,
|
|
1234
|
+
flags: Optional[List[str]] = None,
|
|
1117
1235
|
livecrawl_timeout: Optional[int] = None,
|
|
1118
1236
|
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1237
|
+
filter_empty_results: Optional[bool] = None,
|
|
1119
1238
|
subpages: Optional[int] = None,
|
|
1120
1239
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1121
|
-
filter_empty_results: Optional[bool] = None,
|
|
1122
1240
|
extras: Optional[ExtrasOptions] = None,
|
|
1123
|
-
flags: Optional[List[str]] = None,
|
|
1124
1241
|
) -> SearchResponse[ResultWithText]:
|
|
1125
1242
|
...
|
|
1126
1243
|
|
|
@@ -1141,13 +1258,13 @@ class Exa:
|
|
|
1141
1258
|
exclude_text: Optional[List[str]] = None,
|
|
1142
1259
|
exclude_source_domain: Optional[bool] = None,
|
|
1143
1260
|
category: Optional[str] = None,
|
|
1261
|
+
flags: Optional[List[str]] = None,
|
|
1144
1262
|
subpages: Optional[int] = None,
|
|
1145
1263
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1146
1264
|
livecrawl_timeout: Optional[int] = None,
|
|
1147
1265
|
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1148
1266
|
filter_empty_results: Optional[bool] = None,
|
|
1149
1267
|
extras: Optional[ExtrasOptions] = None,
|
|
1150
|
-
flags: Optional[List[str]] = None,
|
|
1151
1268
|
) -> SearchResponse[ResultWithHighlights]:
|
|
1152
1269
|
...
|
|
1153
1270
|
|
|
@@ -1169,13 +1286,13 @@ class Exa:
|
|
|
1169
1286
|
exclude_text: Optional[List[str]] = None,
|
|
1170
1287
|
exclude_source_domain: Optional[bool] = None,
|
|
1171
1288
|
category: Optional[str] = None,
|
|
1289
|
+
flags: Optional[List[str]] = None,
|
|
1172
1290
|
livecrawl_timeout: Optional[int] = None,
|
|
1173
1291
|
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1292
|
+
filter_empty_results: Optional[bool] = None,
|
|
1174
1293
|
subpages: Optional[int] = None,
|
|
1175
1294
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1176
|
-
filter_empty_results: Optional[bool] = None,
|
|
1177
1295
|
extras: Optional[ExtrasOptions] = None,
|
|
1178
|
-
flags: Optional[List[str]] = None,
|
|
1179
1296
|
) -> SearchResponse[ResultWithTextAndHighlights]:
|
|
1180
1297
|
...
|
|
1181
1298
|
|
|
@@ -1196,13 +1313,13 @@ class Exa:
|
|
|
1196
1313
|
exclude_text: Optional[List[str]] = None,
|
|
1197
1314
|
exclude_source_domain: Optional[bool] = None,
|
|
1198
1315
|
category: Optional[str] = None,
|
|
1316
|
+
flags: Optional[List[str]] = None,
|
|
1199
1317
|
livecrawl_timeout: Optional[int] = None,
|
|
1200
1318
|
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1319
|
+
filter_empty_results: Optional[bool] = None,
|
|
1201
1320
|
subpages: Optional[int] = None,
|
|
1202
1321
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1203
|
-
filter_empty_results: Optional[bool] = None,
|
|
1204
1322
|
extras: Optional[ExtrasOptions] = None,
|
|
1205
|
-
flags: Optional[List[str]] = None,
|
|
1206
1323
|
) -> SearchResponse[ResultWithSummary]:
|
|
1207
1324
|
...
|
|
1208
1325
|
|
|
@@ -1224,13 +1341,13 @@ class Exa:
|
|
|
1224
1341
|
exclude_text: Optional[List[str]] = None,
|
|
1225
1342
|
exclude_source_domain: Optional[bool] = None,
|
|
1226
1343
|
category: Optional[str] = None,
|
|
1344
|
+
flags: Optional[List[str]] = None,
|
|
1227
1345
|
livecrawl_timeout: Optional[int] = None,
|
|
1228
1346
|
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1347
|
+
filter_empty_results: Optional[bool] = None,
|
|
1229
1348
|
subpages: Optional[int] = None,
|
|
1230
1349
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1231
|
-
filter_empty_results: Optional[bool] = None,
|
|
1232
1350
|
extras: Optional[ExtrasOptions] = None,
|
|
1233
|
-
flags: Optional[List[str]] = None,
|
|
1234
1351
|
) -> SearchResponse[ResultWithTextAndSummary]:
|
|
1235
1352
|
...
|
|
1236
1353
|
|
|
@@ -1252,13 +1369,13 @@ class Exa:
|
|
|
1252
1369
|
exclude_text: Optional[List[str]] = None,
|
|
1253
1370
|
exclude_source_domain: Optional[bool] = None,
|
|
1254
1371
|
category: Optional[str] = None,
|
|
1255
|
-
|
|
1372
|
+
flags: Optional[List[str]] = None,
|
|
1256
1373
|
subpages: Optional[int] = None,
|
|
1257
1374
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1375
|
+
livecrawl_timeout: Optional[int] = None,
|
|
1258
1376
|
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1259
1377
|
filter_empty_results: Optional[bool] = None,
|
|
1260
1378
|
extras: Optional[ExtrasOptions] = None,
|
|
1261
|
-
flags: Optional[List[str]] = None,
|
|
1262
1379
|
) -> SearchResponse[ResultWithHighlightsAndSummary]:
|
|
1263
1380
|
...
|
|
1264
1381
|
|
|
@@ -1281,20 +1398,24 @@ class Exa:
|
|
|
1281
1398
|
exclude_text: Optional[List[str]] = None,
|
|
1282
1399
|
exclude_source_domain: Optional[bool] = None,
|
|
1283
1400
|
category: Optional[str] = None,
|
|
1401
|
+
flags: Optional[List[str]] = None,
|
|
1284
1402
|
livecrawl_timeout: Optional[int] = None,
|
|
1403
|
+
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1404
|
+
filter_empty_results: Optional[bool] = None,
|
|
1285
1405
|
subpages: Optional[int] = None,
|
|
1286
1406
|
subpage_target: Optional[Union[str, List[str]]] = None,
|
|
1287
|
-
filter_empty_results: Optional[bool] = None,
|
|
1288
|
-
livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
|
|
1289
1407
|
extras: Optional[ExtrasOptions] = None,
|
|
1290
|
-
flags: Optional[List[str]] = None,
|
|
1291
1408
|
) -> SearchResponse[ResultWithTextAndHighlightsAndSummary]:
|
|
1292
1409
|
...
|
|
1293
1410
|
|
|
1294
1411
|
def find_similar_and_contents(self, url: str, **kwargs):
|
|
1295
1412
|
options = {k: v for k, v in {"url": url, **kwargs}.items() if v is not None}
|
|
1296
1413
|
# Default to text if none specified
|
|
1297
|
-
if
|
|
1414
|
+
if (
|
|
1415
|
+
"text" not in options
|
|
1416
|
+
and "highlights" not in options
|
|
1417
|
+
and "summary" not in options
|
|
1418
|
+
):
|
|
1298
1419
|
options["text"] = True
|
|
1299
1420
|
|
|
1300
1421
|
validate_search_options(
|
|
@@ -1324,9 +1445,9 @@ class Exa:
|
|
|
1324
1445
|
data = self.request("/findSimilar", options)
|
|
1325
1446
|
return SearchResponse(
|
|
1326
1447
|
[Result(**to_snake_case(result)) for result in data["results"]],
|
|
1327
|
-
data
|
|
1328
|
-
data
|
|
1329
|
-
data
|
|
1448
|
+
data.get("autopromptString"),
|
|
1449
|
+
data.get("resolvedSearchType"),
|
|
1450
|
+
data.get("autoDate"),
|
|
1330
1451
|
)
|
|
1331
1452
|
|
|
1332
1453
|
def wrap(self, client: OpenAI):
|
|
@@ -1400,7 +1521,7 @@ class Exa:
|
|
|
1400
1521
|
exa_kwargs=exa_kwargs,
|
|
1401
1522
|
)
|
|
1402
1523
|
|
|
1403
|
-
print("Wrapping OpenAI client with Exa functionality."
|
|
1524
|
+
print("Wrapping OpenAI client with Exa functionality.")
|
|
1404
1525
|
client.chat.completions.create = create_with_rag # type: ignore
|
|
1405
1526
|
|
|
1406
1527
|
return client
|
|
@@ -1444,6 +1565,7 @@ class Exa:
|
|
|
1444
1565
|
completion=completion, exa_result=None
|
|
1445
1566
|
)
|
|
1446
1567
|
|
|
1568
|
+
# We do a search_and_contents automatically
|
|
1447
1569
|
exa_result = self.search_and_contents(query, **exa_kwargs)
|
|
1448
1570
|
exa_str = format_exa_result(exa_result, max_len=max_len)
|
|
1449
1571
|
new_messages = add_message_to_messages(completion, messages, exa_str)
|
|
@@ -1453,3 +1575,51 @@ class Exa:
|
|
|
1453
1575
|
completion=completion, exa_result=exa_result
|
|
1454
1576
|
)
|
|
1455
1577
|
return exa_completion
|
|
1578
|
+
|
|
1579
|
+
@overload
|
|
1580
|
+
def answer(
|
|
1581
|
+
self,
|
|
1582
|
+
query: str,
|
|
1583
|
+
*,
|
|
1584
|
+
expanded_queries_limit: Optional[int] = 1,
|
|
1585
|
+
stream: Optional[bool] = False,
|
|
1586
|
+
include_text: Optional[bool] = False,
|
|
1587
|
+
) -> Union[AnswerResponse, Iterator[Union[str, List[AnswerResult]]]]:
|
|
1588
|
+
...
|
|
1589
|
+
|
|
1590
|
+
def answer(
|
|
1591
|
+
self,
|
|
1592
|
+
query: str,
|
|
1593
|
+
*,
|
|
1594
|
+
expanded_queries_limit: Optional[int] = 1,
|
|
1595
|
+
stream: Optional[bool] = False,
|
|
1596
|
+
include_text: Optional[bool] = False,
|
|
1597
|
+
) -> Union[AnswerResponse, Iterator[Union[str, List[AnswerResult]]]]:
|
|
1598
|
+
"""Generate an answer to a query using Exa's search and LLM capabilities.
|
|
1599
|
+
|
|
1600
|
+
Args:
|
|
1601
|
+
query (str): The query to answer.
|
|
1602
|
+
expanded_queries_limit (int, optional): Maximum number of query variations (0-4). Defaults to 1.
|
|
1603
|
+
stream (bool, optional): Whether to stream the response. Defaults to False.
|
|
1604
|
+
include_text (bool, optional): Whether to include full text in the results. Defaults to False.
|
|
1605
|
+
|
|
1606
|
+
Returns:
|
|
1607
|
+
Union[AnswerResponse, Iterator[Union[str, List[AnswerResult]]]]:
|
|
1608
|
+
- If stream=False, returns an AnswerResponse object containing the answer and sources.
|
|
1609
|
+
- If stream=True, returns an iterator that yields either answer chunks or sources.
|
|
1610
|
+
"""
|
|
1611
|
+
options = {
|
|
1612
|
+
k: v
|
|
1613
|
+
for k, v in locals().items()
|
|
1614
|
+
if k != "self" and v is not None
|
|
1615
|
+
}
|
|
1616
|
+
options = to_camel_case(options)
|
|
1617
|
+
response = self.request("/answer", options)
|
|
1618
|
+
|
|
1619
|
+
if stream:
|
|
1620
|
+
return response
|
|
1621
|
+
|
|
1622
|
+
return AnswerResponse(
|
|
1623
|
+
response["answer"],
|
|
1624
|
+
[AnswerResult(**to_snake_case(result)) for result in response["sources"]]
|
|
1625
|
+
)
|
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: exa-py
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.4
|
|
4
4
|
Summary: Python SDK for Exa API.
|
|
5
|
-
|
|
5
|
+
Home-page: https://github.com/exa-labs/exa-py
|
|
6
|
+
Author: Exa
|
|
6
7
|
Author-email: hello@exa.ai
|
|
7
|
-
|
|
8
|
-
Classifier:
|
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Typing :: Typed
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
9
13
|
Classifier: Programming Language :: Python :: 3.9
|
|
10
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
11
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
12
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
-
Requires-Dist: openai (>=1.48,<2.0)
|
|
15
|
-
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
|
16
|
-
Requires-Dist: typing-extensions (>=4.12.2,<5.0.0)
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: requests
|
|
19
|
+
Requires-Dist: typing-extensions
|
|
20
|
+
Requires-Dist: openai (>=1.10.0)
|
|
18
21
|
|
|
19
22
|
# Exa
|
|
20
23
|
|
|
@@ -87,6 +90,18 @@ exa = Exa(api_key="your-api-key")
|
|
|
87
90
|
results = exa.get_contents(["urls"],
|
|
88
91
|
text={"include_html_tags": True, "max_characters": 1000},
|
|
89
92
|
highlights={"highlights_per_url": 2, "num_sentences": 1, "query": "This is the highlight query:"})
|
|
90
|
-
```
|
|
91
93
|
|
|
94
|
+
# basic answer
|
|
95
|
+
response = exa.answer("This is a query to answer a question")
|
|
96
|
+
|
|
97
|
+
# answer with expanded queries and full text
|
|
98
|
+
response = exa.answer("This is a query to answer a question", expanded_queries_limit=3, include_text=True)
|
|
99
|
+
|
|
100
|
+
# answer with streaming
|
|
101
|
+
response = exa.answer("This is a query to answer with streaming:", stream=True)
|
|
102
|
+
|
|
103
|
+
# Print each chunk as it arrives when answer streaming is enabled
|
|
104
|
+
for chunk in response:
|
|
105
|
+
print(chunk)
|
|
106
|
+
```
|
|
92
107
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
exa_py/__init__.py,sha256=1selemczpRm1y8V9cWNm90LARnU1jbtyp-Qpx3c7cTw,28
|
|
2
|
+
exa_py/api.py,sha256=MiNGWxhy4ppEV5Buo5jqh0kJiPzTZ-DnZKQVQsIzOl4,59489
|
|
3
|
+
exa_py/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
exa_py/utils.py,sha256=Rc1FJjoR9LQ7L_OJM91Sd1GNkbHjcLyEvJENhRix6gc,2405
|
|
5
|
+
exa_py-1.8.4.dist-info/METADATA,sha256=zb1BWHXdwTnZJuhz7HCS0Cqka98BektdVyWw5E32eoE,3494
|
|
6
|
+
exa_py-1.8.4.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
|
7
|
+
exa_py-1.8.4.dist-info/top_level.txt,sha256=Mfkmscdw9HWR1PtVhU1gAiVo6DHu_tyiVdb89gfZBVI,7
|
|
8
|
+
exa_py-1.8.4.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
exa_py
|
exa_py-1.7.3.dist-info/RECORD
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
exa_py/__init__.py,sha256=1selemczpRm1y8V9cWNm90LARnU1jbtyp-Qpx3c7cTw,28
|
|
2
|
-
exa_py/api.py,sha256=s2PzWTN_NSECTlJjEnaN22frTnoxXw0PdO2aalKUX2I,53610
|
|
3
|
-
exa_py/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
exa_py/utils.py,sha256=Rc1FJjoR9LQ7L_OJM91Sd1GNkbHjcLyEvJENhRix6gc,2405
|
|
5
|
-
exa_py-1.7.3.dist-info/METADATA,sha256=tMUP_KFmo-S9zvX72MFY3qW8MIMMj5ZtYUldP_4fTt4,2930
|
|
6
|
-
exa_py-1.7.3.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
|
7
|
-
exa_py-1.7.3.dist-info/RECORD,,
|