-
Notifications
You must be signed in to change notification settings - Fork 44.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(blocks): Add Exa API Blocks (#8835)
Adding Exa API blocks because it does very cool search and web scrapping ### Changes 🏗️ Adding Exa API blocks: Search Added a new calendar and time input Added _auth.py for Exa API too. ### Checklist 📋 #### For code changes: - [ ] I have clearly listed my changes in the PR description - [ ] I have made a test plan - [ ] I have tested my changes according to the test plan: <!-- Put your test plan here: --> - [ ] ... <details> <summary>Example test plan</summary> - [ ] Create from scratch and execute an agent with at least 3 blocks - [ ] Import an agent from file upload, and confirm it executes correctly - [ ] Upload agent to marketplace - [ ] Import an agent from marketplace and confirm it executes correctly - [ ] Edit an agent from monitor, and confirm it executes correctly </details> #### For configuration changes: - [ ] `.env.example` is updated or already compatible with my changes - [ ] `docker-compose.yml` is updated or already compatible with my changes - [ ] I have included a list of my configuration changes in the PR description (under **Changes**) <details> <summary>Examples of configuration changes</summary> - Changing ports - Adding new services that need to communicate with each other - Secrets or environment variable changes - New or infrastructure changes such as databases </details> --------- Co-authored-by: Nicholas Tindle <[email protected]>
- Loading branch information
1 parent
9ad9dd9
commit dcfad26
Showing
6 changed files
with
294 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
from typing import Literal | ||
|
||
from pydantic import SecretStr | ||
|
||
from backend.data.model import APIKeyCredentials, CredentialsField, CredentialsMetaInput | ||
|
||
ExaCredentials = APIKeyCredentials | ||
ExaCredentialsInput = CredentialsMetaInput[ | ||
Literal["exa"], | ||
Literal["api_key"], | ||
] | ||
|
||
TEST_CREDENTIALS = APIKeyCredentials( | ||
id="01234567-89ab-cdef-0123-456789abcdef", | ||
provider="exa", | ||
api_key=SecretStr("mock-exa-api-key"), | ||
title="Mock Exa API key", | ||
expires_at=None, | ||
) | ||
|
||
TEST_CREDENTIALS_INPUT = { | ||
"provider": TEST_CREDENTIALS.provider, | ||
"id": TEST_CREDENTIALS.id, | ||
"type": TEST_CREDENTIALS.type, | ||
"title": TEST_CREDENTIALS.title, | ||
} | ||
|
||
|
||
def ExaCredentialsField() -> ExaCredentialsInput: | ||
"""Creates an Exa credentials input on a block.""" | ||
return CredentialsField( | ||
provider="exa", | ||
supported_credential_types={"api_key"}, | ||
description="The Exa integration requires an API Key.", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
from datetime import datetime | ||
from typing import List | ||
|
||
from pydantic import BaseModel | ||
|
||
from backend.blocks.exa._auth import ( | ||
ExaCredentials, | ||
ExaCredentialsField, | ||
ExaCredentialsInput, | ||
) | ||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema | ||
from backend.data.model import SchemaField | ||
from backend.util.request import requests | ||
|
||
|
||
class ContentSettings(BaseModel): | ||
text: dict = SchemaField( | ||
description="Text content settings", | ||
default={"maxCharacters": 1000, "includeHtmlTags": False}, | ||
) | ||
highlights: dict = SchemaField( | ||
description="Highlight settings", | ||
default={"numSentences": 3, "highlightsPerUrl": 3}, | ||
) | ||
summary: dict = SchemaField( | ||
description="Summary settings", | ||
default={"query": ""}, | ||
) | ||
|
||
|
||
class ExaSearchBlock(Block): | ||
class Input(BlockSchema): | ||
credentials: ExaCredentialsInput = ExaCredentialsField() | ||
query: str = SchemaField(description="The search query") | ||
useAutoprompt: bool = SchemaField( | ||
description="Whether to use autoprompt", | ||
default=True, | ||
) | ||
type: str = SchemaField( | ||
description="Type of search", | ||
default="", | ||
) | ||
category: str = SchemaField( | ||
description="Category to search within", | ||
default="", | ||
) | ||
numResults: int = SchemaField( | ||
description="Number of results to return", | ||
default=10, | ||
) | ||
includeDomains: List[str] = SchemaField( | ||
description="Domains to include in search", | ||
default=[], | ||
) | ||
excludeDomains: List[str] = SchemaField( | ||
description="Domains to exclude from search", | ||
default=[], | ||
) | ||
startCrawlDate: datetime = SchemaField( | ||
description="Start date for crawled content", | ||
) | ||
endCrawlDate: datetime = SchemaField( | ||
description="End date for crawled content", | ||
) | ||
startPublishedDate: datetime = SchemaField( | ||
description="Start date for published content", | ||
) | ||
endPublishedDate: datetime = SchemaField( | ||
description="End date for published content", | ||
) | ||
includeText: List[str] = SchemaField( | ||
description="Text patterns to include", | ||
default=[], | ||
) | ||
excludeText: List[str] = SchemaField( | ||
description="Text patterns to exclude", | ||
default=[], | ||
) | ||
contents: ContentSettings = SchemaField( | ||
description="Content retrieval settings", | ||
default=ContentSettings(), | ||
) | ||
|
||
class Output(BlockSchema): | ||
results: list = SchemaField( | ||
description="List of search results", | ||
default=[], | ||
) | ||
|
||
def __init__(self): | ||
super().__init__( | ||
id="996cec64-ac40-4dde-982f-b0dc60a5824d", | ||
description="Searches the web using Exa's advanced search API", | ||
categories={BlockCategory.SEARCH}, | ||
input_schema=ExaSearchBlock.Input, | ||
output_schema=ExaSearchBlock.Output, | ||
) | ||
|
||
def run( | ||
self, input_data: Input, *, credentials: ExaCredentials, **kwargs | ||
) -> BlockOutput: | ||
url = "https://api.exa.ai/search" | ||
headers = { | ||
"Content-Type": "application/json", | ||
"x-api-key": credentials.api_key.get_secret_value(), | ||
} | ||
|
||
payload = { | ||
"query": input_data.query, | ||
"useAutoprompt": input_data.useAutoprompt, | ||
"numResults": input_data.numResults, | ||
"contents": { | ||
"text": {"maxCharacters": 1000, "includeHtmlTags": False}, | ||
"highlights": { | ||
"numSentences": 3, | ||
"highlightsPerUrl": 3, | ||
}, | ||
"summary": {"query": ""}, | ||
}, | ||
} | ||
|
||
# Add dates if they exist | ||
date_fields = [ | ||
"startCrawlDate", | ||
"endCrawlDate", | ||
"startPublishedDate", | ||
"endPublishedDate", | ||
] | ||
for field in date_fields: | ||
value = getattr(input_data, field, None) | ||
if value: | ||
payload[field] = value.strftime("%Y-%m-%dT%H:%M:%S.000Z") | ||
|
||
# Add other fields | ||
optional_fields = [ | ||
"type", | ||
"category", | ||
"includeDomains", | ||
"excludeDomains", | ||
"includeText", | ||
"excludeText", | ||
] | ||
|
||
for field in optional_fields: | ||
value = getattr(input_data, field) | ||
if value: # Only add non-empty values | ||
payload[field] = value | ||
|
||
try: | ||
response = requests.post(url, headers=headers, json=payload) | ||
response.raise_for_status() | ||
data = response.json() | ||
# Extract just the results array from the response | ||
yield "results", data.get("results", []) | ||
except Exception as e: | ||
yield "error", str(e) | ||
yield "results", [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters