File size: 7,642 Bytes
e0ab47e 0199a4f e0ab47e 0199a4f e0ab47e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
from smolagents import CodeAgent, DuckDuckGoSearchTool, load_tool, tool
import datetime
import requests
import pytz
import yaml
from tools.final_answer import FinalAnswerTool
from bs4 import BeautifulSoup
from azure.ai.inference import ChatCompletionsClient
from azure.ai.inference.models import SystemMessage, UserMessage
from azure.core.credentials import AzureKeyCredential
from Gradio_UI import GradioUI
from dotenv import load_dotenv
import os
# Simple response object to match smolagents expectations
class ChatMessage:
def __init__(self, content):
self.content = content
# Custom Azure Model class for smolagents
class AzureModel:
def __init__(self, endpoint, token, model_name, max_tokens=2096, temperature=0.5):
self.client = ChatCompletionsClient(
endpoint=endpoint,
credential=AzureKeyCredential(token),
)
self.model_name = model_name
self.max_tokens = max_tokens
self.temperature = temperature
def __call__(self, messages, **kwargs):
# Convert smolagents message format to Azure format
azure_messages = []
if isinstance(messages, list):
for msg in messages:
if isinstance(msg, dict):
# Extract role (convert enum to string if needed)
role = str(msg.get('role', 'user')).lower()
if 'system' in role:
role = 'system'
elif 'user' in role:
role = 'user'
elif 'assistant' in role:
role = 'assistant'
else:
role = 'user' # default to user
# Extract content - handle complex content structure
content = msg.get('content', '')
# If content is a list (complex format from smolagents)
if isinstance(content, list):
# Extract text from the content list
text_content = ""
for item in content:
if isinstance(item, dict) and item.get('type') == 'text':
text_content += item.get('text', '')
content = text_content
# Convert to string if not already
content = str(content) if content else ""
# Create appropriate Azure message
if role == 'system':
azure_messages.append(SystemMessage(content))
else:
azure_messages.append(UserMessage(content))
elif isinstance(msg, str):
azure_messages.append(UserMessage(msg))
else:
azure_messages.append(UserMessage(str(msg)))
else:
azure_messages.append(UserMessage(str(messages)))
# Ensure we have at least one message
if not azure_messages:
azure_messages.append(UserMessage("Hello"))
try:
# Make the API call
response = self.client.complete(
messages=azure_messages,
temperature=kwargs.get('temperature', self.temperature),
top_p=kwargs.get('top_p', 1.0),
max_tokens=kwargs.get('max_tokens', self.max_tokens),
model=self.model_name
)
return ChatMessage(response.choices[0].message.content)
except Exception as e:
print(f"Azure API Error: {e}")
return ChatMessage(f"Error calling Azure API: {str(e)}")
# Azure API configuration
load_dotenv() # Loads from .env by default
endpoint = os.getenv("AZURE_ENDPOINT")
model_name = os.getenv("AZURE_MODEL_NAME")
token = os.getenv("AZURE_TOKEN")
@tool
def summarize_webpage(url: str) -> str:
"""A tool that fetches and summarizes text content from a webpage.
Args:
url: A valid URL to a webpage.
"""
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
response = requests.get(url, timeout=10, headers=headers)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
# Remove script and style elements
for script in soup(["script", "style"]):
script.decompose()
paragraphs = soup.find_all('p')
text = ' '.join(p.get_text().strip() for p in paragraphs[:30] if p.get_text().strip())
if not text:
# Fallback to other text elements if no paragraphs found
text = soup.get_text()[:2000]
return f"Summary of content from {url}: {text[:700]}..."
except requests.RequestException as e:
return f"Failed to fetch the webpage {url}: Network error - {str(e)}"
except Exception as e:
return f"Failed to process the webpage {url}: {str(e)}"
@tool
def get_current_time_in_timezone(timezone: str) -> str:
"""A tool that fetches the current local time in a specified timezone.
Args:
timezone: A string representing a valid timezone (e.g., 'America/New_York').
"""
try:
# Create timezone object
tz = pytz.timezone(timezone)
# Get current time in that timezone
local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
return f"The current local time in {timezone} is: {local_time}"
except pytz.exceptions.UnknownTimeZoneError:
return f"Error: Unknown timezone '{timezone}'. Please provide a valid timezone."
except Exception as e:
return f"Error fetching time for timezone '{timezone}': {str(e)}"
@tool
def search_web(query: str) -> str:
"""A tool that searches the web using DuckDuckGo.
Args:
query: The search query string.
"""
try:
search_tool = DuckDuckGoSearchTool()
results = search_tool(query)
return f"Search results for '{query}': {results}"
except Exception as e:
return f"Error searching for '{query}': {str(e)}"
# Initialize final answer tool
final_answer = FinalAnswerTool()
# Create Azure model instance
model = AzureModel(
endpoint=endpoint,
token=token,
model_name=model_name,
max_tokens=2096,
temperature=0.5
)
# Load prompt templates with error handling
try:
with open("prompts.yaml", 'r') as stream:
prompt_templates = yaml.safe_load(stream)
except FileNotFoundError:
print("Warning: prompts.yaml not found. Using default prompts.")
prompt_templates = None
except yaml.YAMLError as e:
print(f"Warning: Error parsing prompts.yaml: {e}. Using default prompts.")
prompt_templates = None
# Create agent with all tools
agent = CodeAgent(
model=model,
tools=[final_answer, summarize_webpage, get_current_time_in_timezone, search_web],
max_steps=6,
verbosity_level=1,
grammar=None,
planning_interval=None,
name="WebAgent",
description="An AI agent that can search the web, summarize webpages, and get current time information."
)
# Launch the Gradio UI
if __name__ == "__main__":
try:
GradioUI(agent).launch()
except Exception as e:
print(f"Error launching Gradio UI: {e}")
print("Make sure all dependencies are installed and the Gradio_UI module is available.") |