Spaces:
Runtime error
Runtime error
Fix version conflict
Browse files- get_tools_working.py +77 -32
- requirements.txt +3 -5
get_tools_working.py
CHANGED
|
@@ -22,13 +22,13 @@ import requests
|
|
| 22 |
import sys
|
| 23 |
import xml.etree.ElementTree as ET
|
| 24 |
from botocore.config import Config as BotocoreConfig
|
|
|
|
| 25 |
|
| 26 |
from strands import Agent, tool
|
| 27 |
from strands.models import BedrockModel
|
| 28 |
from strands_tools import workflow
|
| 29 |
from strands_tools import rss
|
| 30 |
from strands_tools import http_request
|
| 31 |
-
from brave import Brave
|
| 32 |
|
| 33 |
from sendgrid import SendGridAPIClient
|
| 34 |
from sendgrid.helpers.mail import Mail
|
|
@@ -38,7 +38,7 @@ os.environ.setdefault("BYPASS_TOOL_CONSENT", "true")
|
|
| 38 |
|
| 39 |
@tool
|
| 40 |
def brave_search(query: str, count: int = 10) -> str:
|
| 41 |
-
"""Search the web using Brave Search API for news and information"""
|
| 42 |
|
| 43 |
print(f"π Searching Brave for: '{query}' (count: {count})")
|
| 44 |
|
|
@@ -48,42 +48,85 @@ def brave_search(query: str, count: int = 10) -> str:
|
|
| 48 |
raise ValueError("BRAVE_API_KEY environment variable is not set")
|
| 49 |
|
| 50 |
try:
|
| 51 |
-
#
|
| 52 |
-
|
| 53 |
|
| 54 |
-
#
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
|
| 57 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
formatted_results = []
|
| 59 |
|
| 60 |
-
|
| 61 |
-
|
|
|
|
|
|
|
| 62 |
formatted_result = f"""
|
| 63 |
Result {idx}:
|
| 64 |
-
Title: {result.title}
|
| 65 |
-
URL: {result.url}
|
| 66 |
-
Description: {result.description}
|
| 67 |
---"""
|
| 68 |
formatted_results.append(formatted_result)
|
| 69 |
|
| 70 |
-
#
|
| 71 |
-
if
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
|
|
|
|
|
|
| 75 |
News {idx}:
|
| 76 |
-
Title: {news.title}
|
| 77 |
-
URL: {news.url}
|
| 78 |
-
Description: {news.description}
|
| 79 |
-
Age: {
|
| 80 |
---"""
|
| 81 |
-
|
| 82 |
|
| 83 |
final_result = "\n".join(formatted_results) if formatted_results else "No results found"
|
| 84 |
-
print(f"β
Found {len(formatted_results)} results from Brave Search")
|
| 85 |
return final_result
|
| 86 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
except Exception as e:
|
| 88 |
error_msg = f"Error performing Brave search: {str(e)}"
|
| 89 |
print(f"β {error_msg}")
|
|
@@ -156,7 +199,7 @@ def get_leadgen_agent(user_email: str):
|
|
| 156 |
|
| 157 |
|
| 158 |
# Generic system instructions for Docker environment with LinkedIn profile search and outreach
|
| 159 |
-
autonomous_system_prompt = """
|
| 160 |
CRITICAL: You are running in a Docker container environment and MUST operate completely autonomously without ANY user input or interaction.
|
| 161 |
|
| 162 |
ENVIRONMENT CONTEXT:
|
|
@@ -201,21 +244,21 @@ AVAILABLE TOOLS AND BEST PRACTICES:
|
|
| 201 |
- Examples:
|
| 202 |
```
|
| 203 |
# Fetch a web page
|
| 204 |
-
http_request({
|
| 205 |
"method": "GET",
|
| 206 |
"url": "https://example.com/page",
|
| 207 |
"convert_to_markdown": True
|
| 208 |
-
})
|
| 209 |
|
| 210 |
# API call with authentication
|
| 211 |
-
http_request({
|
| 212 |
"method": "POST",
|
| 213 |
"url": "https://api.example.com/endpoint",
|
| 214 |
-
"headers": {"Content-Type": "application/json"},
|
| 215 |
-
"body": json.dumps({"key": "value"}),
|
| 216 |
"auth_type": "Bearer",
|
| 217 |
"auth_token": "your_token"
|
| 218 |
-
})
|
| 219 |
```
|
| 220 |
|
| 221 |
3. RSS TOOL (rss) - Use for news feeds and RSS content management
|
|
@@ -223,11 +266,11 @@ AVAILABLE TOOLS AND BEST PRACTICES:
|
|
| 223 |
- Examples:
|
| 224 |
```
|
| 225 |
# Fetch without subscribing
|
| 226 |
-
rss({
|
| 227 |
"action": "fetch",
|
| 228 |
"url": "https://example.com/feed",
|
| 229 |
"max_entries": 3
|
| 230 |
-
})
|
| 231 |
```
|
| 232 |
|
| 233 |
4. EMAIL TOOL (send_email) - Use for sending reports and notifications
|
|
@@ -321,6 +364,8 @@ IMPORTANT: For each lead found, you MUST:
|
|
| 321 |
- Reference recent company news or developments
|
| 322 |
- Always send a final email report with all leads, LinkedIn URLs, and outreach messages
|
| 323 |
|
|
|
|
|
|
|
| 324 |
Remember: You are in a server environment - operate completely independently without any user interaction. Focus on finding LinkedIn profiles and crafting personalized outreach messages for recruitment leads.
|
| 325 |
"""
|
| 326 |
|
|
|
|
| 22 |
import sys
|
| 23 |
import xml.etree.ElementTree as ET
|
| 24 |
from botocore.config import Config as BotocoreConfig
|
| 25 |
+
from datetime import date
|
| 26 |
|
| 27 |
from strands import Agent, tool
|
| 28 |
from strands.models import BedrockModel
|
| 29 |
from strands_tools import workflow
|
| 30 |
from strands_tools import rss
|
| 31 |
from strands_tools import http_request
|
|
|
|
| 32 |
|
| 33 |
from sendgrid import SendGridAPIClient
|
| 34 |
from sendgrid.helpers.mail import Mail
|
|
|
|
| 38 |
|
| 39 |
@tool
|
| 40 |
def brave_search(query: str, count: int = 10) -> str:
|
| 41 |
+
"""Search the web using Brave Search API for news and information via direct HTTP requests"""
|
| 42 |
|
| 43 |
print(f"π Searching Brave for: '{query}' (count: {count})")
|
| 44 |
|
|
|
|
| 48 |
raise ValueError("BRAVE_API_KEY environment variable is not set")
|
| 49 |
|
| 50 |
try:
|
| 51 |
+
# Brave Search API endpoint
|
| 52 |
+
api_url = "https://api.search.brave.com/res/v1/web/search"
|
| 53 |
|
| 54 |
+
# Set up headers with API key
|
| 55 |
+
headers = {
|
| 56 |
+
"Accept": "application/json",
|
| 57 |
+
"Accept-Encoding": "gzip",
|
| 58 |
+
"X-Subscription-Token": brave_api_key
|
| 59 |
+
}
|
| 60 |
|
| 61 |
+
# Set up query parameters
|
| 62 |
+
params = {
|
| 63 |
+
"q": query,
|
| 64 |
+
"count": min(count, 20), # API maximum is 20
|
| 65 |
+
"offset": 0,
|
| 66 |
+
"safesearch": "moderate",
|
| 67 |
+
"freshness": "",
|
| 68 |
+
"text_decorations": True,
|
| 69 |
+
"spellcheck": True,
|
| 70 |
+
"result_filter": "web,news" # Include both web and news results
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
# Make the HTTP request
|
| 74 |
+
print(f"π‘ Making request to Brave Search API...")
|
| 75 |
+
response = requests.get(api_url, headers=headers, params=params, timeout=30)
|
| 76 |
+
|
| 77 |
+
# Check if request was successful
|
| 78 |
+
if response.status_code != 200:
|
| 79 |
+
error_msg = f"Brave Search API returned status {response.status_code}: {response.text}"
|
| 80 |
+
print(f"β {error_msg}")
|
| 81 |
+
return error_msg
|
| 82 |
+
|
| 83 |
+
# Parse JSON response
|
| 84 |
+
search_data = response.json()
|
| 85 |
formatted_results = []
|
| 86 |
|
| 87 |
+
# Process web results
|
| 88 |
+
if "web" in search_data and "results" in search_data["web"]:
|
| 89 |
+
web_results = search_data["web"]["results"]
|
| 90 |
+
for idx, result in enumerate(web_results[:count], 1):
|
| 91 |
formatted_result = f"""
|
| 92 |
Result {idx}:
|
| 93 |
+
Title: {result.get('title', 'N/A')}
|
| 94 |
+
URL: {result.get('url', 'N/A')}
|
| 95 |
+
Description: {result.get('description', 'N/A')}
|
| 96 |
---"""
|
| 97 |
formatted_results.append(formatted_result)
|
| 98 |
|
| 99 |
+
# Process news results if available
|
| 100 |
+
if "news" in search_data and "results" in search_data["news"]:
|
| 101 |
+
news_results = search_data["news"]["results"]
|
| 102 |
+
if news_results:
|
| 103 |
+
formatted_results.append("\nποΈ NEWS RESULTS:")
|
| 104 |
+
for idx, news in enumerate(news_results[:count], 1):
|
| 105 |
+
formatted_result = f"""
|
| 106 |
News {idx}:
|
| 107 |
+
Title: {news.get('title', 'N/A')}
|
| 108 |
+
URL: {news.get('url', 'N/A')}
|
| 109 |
+
Description: {news.get('description', 'N/A')}
|
| 110 |
+
Age: {news.get('age', 'N/A')}
|
| 111 |
---"""
|
| 112 |
+
formatted_results.append(formatted_result)
|
| 113 |
|
| 114 |
final_result = "\n".join(formatted_results) if formatted_results else "No results found"
|
| 115 |
+
print(f"β
Found {len(formatted_results)} results from Brave Search API")
|
| 116 |
return final_result
|
| 117 |
|
| 118 |
+
except requests.exceptions.Timeout:
|
| 119 |
+
error_msg = "Request to Brave Search API timed out"
|
| 120 |
+
print(f"β {error_msg}")
|
| 121 |
+
return error_msg
|
| 122 |
+
except requests.exceptions.RequestException as e:
|
| 123 |
+
error_msg = f"Network error with Brave Search API: {str(e)}"
|
| 124 |
+
print(f"β {error_msg}")
|
| 125 |
+
return error_msg
|
| 126 |
+
except json.JSONDecodeError as e:
|
| 127 |
+
error_msg = f"Failed to parse Brave Search API response: {str(e)}"
|
| 128 |
+
print(f"β {error_msg}")
|
| 129 |
+
return error_msg
|
| 130 |
except Exception as e:
|
| 131 |
error_msg = f"Error performing Brave search: {str(e)}"
|
| 132 |
print(f"β {error_msg}")
|
|
|
|
| 199 |
|
| 200 |
|
| 201 |
# Generic system instructions for Docker environment with LinkedIn profile search and outreach
|
| 202 |
+
autonomous_system_prompt = f"""
|
| 203 |
CRITICAL: You are running in a Docker container environment and MUST operate completely autonomously without ANY user input or interaction.
|
| 204 |
|
| 205 |
ENVIRONMENT CONTEXT:
|
|
|
|
| 244 |
- Examples:
|
| 245 |
```
|
| 246 |
# Fetch a web page
|
| 247 |
+
http_request({{
|
| 248 |
"method": "GET",
|
| 249 |
"url": "https://example.com/page",
|
| 250 |
"convert_to_markdown": True
|
| 251 |
+
}})
|
| 252 |
|
| 253 |
# API call with authentication
|
| 254 |
+
http_request({{
|
| 255 |
"method": "POST",
|
| 256 |
"url": "https://api.example.com/endpoint",
|
| 257 |
+
"headers": {{"Content-Type": "application/json"}},
|
| 258 |
+
"body": json.dumps({{"key": "value"}}),
|
| 259 |
"auth_type": "Bearer",
|
| 260 |
"auth_token": "your_token"
|
| 261 |
+
}})
|
| 262 |
```
|
| 263 |
|
| 264 |
3. RSS TOOL (rss) - Use for news feeds and RSS content management
|
|
|
|
| 266 |
- Examples:
|
| 267 |
```
|
| 268 |
# Fetch without subscribing
|
| 269 |
+
rss({{
|
| 270 |
"action": "fetch",
|
| 271 |
"url": "https://example.com/feed",
|
| 272 |
"max_entries": 3
|
| 273 |
+
}})
|
| 274 |
```
|
| 275 |
|
| 276 |
4. EMAIL TOOL (send_email) - Use for sending reports and notifications
|
|
|
|
| 364 |
- Reference recent company news or developments
|
| 365 |
- Always send a final email report with all leads, LinkedIn URLs, and outreach messages
|
| 366 |
|
| 367 |
+
IMPORTANT : When you need to use a date , month or year be aware today is {str(date.today())}
|
| 368 |
+
|
| 369 |
Remember: You are in a server environment - operate completely independently without any user interaction. Focus on finding LinkedIn profiles and crafting personalized outreach messages for recruitment leads.
|
| 370 |
"""
|
| 371 |
|
requirements.txt
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
|
|
|
|
|
| 1 |
huggingface_hub==0.25.2
|
| 2 |
gradio
|
| 3 |
strands-agents
|
| 4 |
-
strands-agents-tools
|
| 5 |
botocore
|
| 6 |
pandas
|
| 7 |
requests
|
|
@@ -9,8 +11,4 @@ sendgrid
|
|
| 9 |
uvicorn
|
| 10 |
fastapi
|
| 11 |
bedrock_agentcore
|
| 12 |
-
playwright
|
| 13 |
nest_asyncio
|
| 14 |
-
brave-search
|
| 15 |
-
httpx
|
| 16 |
-
tenacity
|
|
|
|
| 1 |
+
# Force tenacity version first to resolve conflicts
|
| 2 |
+
tenacity==9.1.2
|
| 3 |
huggingface_hub==0.25.2
|
| 4 |
gradio
|
| 5 |
strands-agents
|
| 6 |
+
strands-agents-tools[workflow, rss, http_request]
|
| 7 |
botocore
|
| 8 |
pandas
|
| 9 |
requests
|
|
|
|
| 11 |
uvicorn
|
| 12 |
fastapi
|
| 13 |
bedrock_agentcore
|
|
|
|
| 14 |
nest_asyncio
|
|
|
|
|
|
|
|
|