exa-py 1.7.3__py3-none-any.whl → 1.8.3__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
|
|
|
@@ -494,6 +495,56 @@ class ResultWithTextAndHighlightsAndSummary(_Result):
|
|
|
494
495
|
f"Summary: {self.summary}\n"
|
|
495
496
|
)
|
|
496
497
|
|
|
498
|
+
@dataclass
|
|
499
|
+
class AnswerResult:
|
|
500
|
+
"""A class representing a source result for an answer.
|
|
501
|
+
|
|
502
|
+
Attributes:
|
|
503
|
+
title (str): The title of the search result.
|
|
504
|
+
url (str): The URL of the search result.
|
|
505
|
+
id (str): The temporary ID for the document.
|
|
506
|
+
published_date (str, optional): An estimate of the creation date, from parsing HTML content.
|
|
507
|
+
author (str, optional): If available, the author of the content.
|
|
508
|
+
"""
|
|
509
|
+
|
|
510
|
+
url: str
|
|
511
|
+
id: str
|
|
512
|
+
title: Optional[str] = None
|
|
513
|
+
published_date: Optional[str] = None
|
|
514
|
+
author: Optional[str] = None
|
|
515
|
+
|
|
516
|
+
def __init__(self, **kwargs):
|
|
517
|
+
self.url = kwargs['url']
|
|
518
|
+
self.id = kwargs['id']
|
|
519
|
+
self.title = kwargs.get('title')
|
|
520
|
+
self.published_date = kwargs.get('published_date')
|
|
521
|
+
self.author = kwargs.get('author')
|
|
522
|
+
|
|
523
|
+
def __str__(self):
|
|
524
|
+
return (
|
|
525
|
+
f"Title: {self.title}\n"
|
|
526
|
+
f"URL: {self.url}\n"
|
|
527
|
+
f"ID: {self.id}\n"
|
|
528
|
+
f"Published Date: {self.published_date}\n"
|
|
529
|
+
f"Author: {self.author}\n"
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
@dataclass
|
|
533
|
+
class AnswerResponse:
|
|
534
|
+
"""A class representing the response for an answer operation.
|
|
535
|
+
|
|
536
|
+
Attributes:
|
|
537
|
+
answer (str): The generated answer.
|
|
538
|
+
sources (List[AnswerResult]): A list of sources used to generate the answer.
|
|
539
|
+
"""
|
|
540
|
+
|
|
541
|
+
answer: str
|
|
542
|
+
sources: List[AnswerResult]
|
|
543
|
+
|
|
544
|
+
def __str__(self):
|
|
545
|
+
output = f"Answer: {self.answer}\n\nSources:\n"
|
|
546
|
+
output += "\n\n".join(str(source) for source in self.sources)
|
|
547
|
+
return output
|
|
497
548
|
|
|
498
549
|
T = TypeVar("T")
|
|
499
550
|
|
|
@@ -548,7 +599,7 @@ class Exa:
|
|
|
548
599
|
self,
|
|
549
600
|
api_key: Optional[str],
|
|
550
601
|
base_url: str = "https://api.exa.ai",
|
|
551
|
-
user_agent: str = "exa-py 1.
|
|
602
|
+
user_agent: str = "exa-py 1.8.3",
|
|
552
603
|
):
|
|
553
604
|
"""Initialize the Exa client with the provided API key and optional base URL and user agent.
|
|
554
605
|
|
|
@@ -568,11 +619,15 @@ class Exa:
|
|
|
568
619
|
self.headers = {"x-api-key": api_key, "User-Agent": user_agent}
|
|
569
620
|
|
|
570
621
|
def request(self, endpoint: str, data):
|
|
622
|
+
if data.get("stream"):
|
|
623
|
+
res = requests.post(self.base_url + endpoint, json=data, headers=self.headers, stream=True)
|
|
624
|
+
if res.status_code != 200:
|
|
625
|
+
raise ValueError(f"Request failed with status code {res.status_code}: {res.text}")
|
|
626
|
+
return (line.decode('utf-8') for line in res.iter_lines() if line)
|
|
627
|
+
|
|
571
628
|
res = requests.post(self.base_url + endpoint, json=data, headers=self.headers)
|
|
572
629
|
if res.status_code != 200:
|
|
573
|
-
raise ValueError(
|
|
574
|
-
f"Request failed with status code {res.status_code}: {res.text}"
|
|
575
|
-
)
|
|
630
|
+
raise ValueError(f"Request failed with status code {res.status_code}: {res.text}")
|
|
576
631
|
return res.json()
|
|
577
632
|
|
|
578
633
|
def search(
|
|
@@ -1453,3 +1508,50 @@ class Exa:
|
|
|
1453
1508
|
completion=completion, exa_result=exa_result
|
|
1454
1509
|
)
|
|
1455
1510
|
return exa_completion
|
|
1511
|
+
|
|
1512
|
+
@overload
|
|
1513
|
+
def answer(
|
|
1514
|
+
self,
|
|
1515
|
+
query: str,
|
|
1516
|
+
*,
|
|
1517
|
+
expanded_queries_limit: Optional[int] = 1,
|
|
1518
|
+
stream: Optional[bool] = False,
|
|
1519
|
+
include_text: Optional[bool] = False,
|
|
1520
|
+
) -> Union[AnswerResponse, Iterator[Union[str, List[AnswerResult]]]]:
|
|
1521
|
+
...
|
|
1522
|
+
|
|
1523
|
+
def answer(
|
|
1524
|
+
self,
|
|
1525
|
+
query: str,
|
|
1526
|
+
*,
|
|
1527
|
+
expanded_queries_limit: Optional[int] = 1,
|
|
1528
|
+
stream: Optional[bool] = False,
|
|
1529
|
+
include_text: Optional[bool] = False,
|
|
1530
|
+
) -> Union[AnswerResponse, Iterator[Union[str, List[AnswerResult]]]]:
|
|
1531
|
+
"""Generate an answer to a query using Exa's search and LLM capabilities.
|
|
1532
|
+
|
|
1533
|
+
Args:
|
|
1534
|
+
query (str): The query to answer.
|
|
1535
|
+
expanded_queries_limit (int, optional): Maximum number of query variations (0-4). Defaults to 1.
|
|
1536
|
+
stream (bool, optional): Whether to stream the response. Defaults to False.
|
|
1537
|
+
include_text (bool, optional): Whether to include full text in the results. Defaults to False.
|
|
1538
|
+
|
|
1539
|
+
Returns:
|
|
1540
|
+
Union[AnswerResponse, Iterator[Union[str, List[AnswerResult]]]]: Either an AnswerResponse object containing the answer and sources,
|
|
1541
|
+
or an iterator that yields either answer chunks or sources when streaming is enabled.
|
|
1542
|
+
"""
|
|
1543
|
+
options = {
|
|
1544
|
+
k: v
|
|
1545
|
+
for k, v in locals().items()
|
|
1546
|
+
if k != "self" and v is not None
|
|
1547
|
+
}
|
|
1548
|
+
options = to_camel_case(options)
|
|
1549
|
+
response = self.request("/answer", options)
|
|
1550
|
+
|
|
1551
|
+
if stream:
|
|
1552
|
+
return response
|
|
1553
|
+
|
|
1554
|
+
return AnswerResponse(
|
|
1555
|
+
response["answer"],
|
|
1556
|
+
[AnswerResult(**to_snake_case(result)) for result in response["sources"]]
|
|
1557
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: exa-py
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.3
|
|
4
4
|
Summary: Python SDK for Exa API.
|
|
5
5
|
Author: Exa AI
|
|
6
6
|
Author-email: hello@exa.ai
|
|
@@ -87,6 +87,19 @@ exa = Exa(api_key="your-api-key")
|
|
|
87
87
|
results = exa.get_contents(["urls"],
|
|
88
88
|
text={"include_html_tags": True, "max_characters": 1000},
|
|
89
89
|
highlights={"highlights_per_url": 2, "num_sentences": 1, "query": "This is the highlight query:"})
|
|
90
|
+
|
|
91
|
+
# basic answer
|
|
92
|
+
response = exa.answer("This is a query to answer a question")
|
|
93
|
+
|
|
94
|
+
# answer with expanded queries and full text
|
|
95
|
+
response = exa.answer("This is a query to answer a question", expanded_queries_limit=3, include_text=True)
|
|
96
|
+
|
|
97
|
+
# answer with streaming
|
|
98
|
+
response = exa.answer("This is a query to answer with streaming:", stream=True)
|
|
99
|
+
|
|
100
|
+
# Print each chunk as it arrives when answer streaming is enabled
|
|
101
|
+
for chunk in response:
|
|
102
|
+
print(chunk)
|
|
90
103
|
```
|
|
91
104
|
|
|
92
105
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
exa_py/__init__.py,sha256=1selemczpRm1y8V9cWNm90LARnU1jbtyp-Qpx3c7cTw,28
|
|
2
|
+
exa_py/api.py,sha256=1Bc9S8OMgGwtih1hXqhYzv54d2Sj04EunMuNoDuqqrg,57257
|
|
3
|
+
exa_py/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
exa_py/utils.py,sha256=Rc1FJjoR9LQ7L_OJM91Sd1GNkbHjcLyEvJENhRix6gc,2405
|
|
5
|
+
exa_py-1.8.3.dist-info/METADATA,sha256=Tp7sUiNVUCyL37ZcfL7v0goOSHn0q35vg-qrYLYAG2I,3389
|
|
6
|
+
exa_py-1.8.3.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
|
7
|
+
exa_py-1.8.3.dist-info/RECORD,,
|
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,,
|
|
File without changes
|