# Upsonic Docs: Create Custom Tools
# https://docs.upsonic.ai/guides/create_custom_tools
# Imports
from upsonic import Agent, Task
from upsonic.tools import tool
from typing import Dict, List, Any
import requests
from bs4 import BeautifulSoup
import time
# Tool 1: Basic Website Content Fetcher
@tool
async def fetch_website_content(url: str) -> Dict[str, Any]:
"""
Fetches and returns the HTML content of a website.
Args:
url: The website URL to fetch content from
Returns:
Dictionary containing 'status', 'content', 'headers', and 'response_time'
Raises:
requests.RequestException: If the request fails
ValueError: If the URL is invalid
"""
start_time = time.time()
try:
response = requests.get(url, timeout=30)
response.raise_for_status()
return {
"status": "success",
"content": response.text,
"headers": dict(response.headers),
"response_time": time.time() - start_time
}
except requests.RequestException as e:
return {
"status": "error",
"error": str(e),
"response_time": time.time() - start_time
}
# Tool 2: SEO Analysis Tool with Human-in-the-Loop via Hooks
from upsonic.tools.tool import ToolHooks
def before_analysis_hook(html_content: str):
"""Hook that runs before SEO analysis to get user confirmation."""
print(f"🔍 About to start SEO analysis on content ({len(html_content)} characters)")
# Ask user for confirmation
user_input = input("Do you want to proceed with SEO analysis? (y/n): ").lower().strip()
if user_input != 'y':
raise Exception("Not allowed, rejected by user")
print("📊 User approved. Starting SEO analysis...")
def after_analysis_hook(result):
"""Hook that runs after SEO analysis - currently not used."""
pass
@tool(tool_hooks=ToolHooks(before=before_analysis_hook, after=after_analysis_hook))
async def analyze_seo_metrics(html_content: str) -> Dict[str, Any]:
"""
Analyzes HTML content for SEO metrics with human-in-the-loop hooks.
Args:
html_content: The HTML content to analyze
Returns:
Dictionary containing enhanced SEO metrics, recommendations, and priority actions
"""
soup = BeautifulSoup(html_content, 'html.parser')
# Extract SEO elements
title = soup.find('title')
meta_description = soup.find('meta', attrs={'name': 'description'})
h1_tags = soup.find_all('h1')
seo_score = 0
recommendations = []
# Analyze title
if title and title.text.strip():
seo_score += 30
if len(title.text) > 60:
recommendations.append("Title is too long (should be under 60 characters)")
else:
recommendations.append("Missing title tag")
# Analyze meta description
if meta_description and meta_description.get('content'):
seo_score += 30
else:
recommendations.append("Missing meta description")
# Analyze H1 tags
if h1_tags:
seo_score += 40
if len(h1_tags) > 1:
recommendations.append("Multiple H1 tags found (should have only one)")
else:
recommendations.append("Missing H1 tag")
return {
"seo_score": seo_score,
"title": title.text.strip() if title else None,
"meta_description": meta_description.get('content') if meta_description else None,
"h1_count": len(h1_tags),
"recommendations": recommendations
}
# Agent Creation with Custom Tools
website_analyzer_agent = Agent(
name="Website Analysis Expert",
role="Website Performance and SEO Specialist",
goal="Provide comprehensive website analysis with actionable insights for optimization"
)
# Example Task Using Custom Tools
analysis_task = Task(
description="Analyze the website 'example.com' for SEO optimization",
tools=[
fetch_website_content,
analyze_seo_metrics
]
)
# Execute the analysis
result = website_analyzer_agent.do(analysis_task)
print("Analysis Complete:", result)