zvl's picture
Update app.py
d85e8b1 verified
raw
history blame
6.51 kB
from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel, load_tool, tool
import datetime
import requests
import pytz
import yaml
import os
import nltk
from bs4 import BeautifulSoup
from nltk.tokenize import sent_tokenize
from tools.final_answer import FinalAnswerTool
from Gradio_UI import GradioUI
# Descargar tokenizer de NLTK si no está disponible
nltk.download("punkt")
# Configurar el modelo de resumen desde Hugging Face en SmolAgents
model = HfApiModel(
max_tokens=2096,
temperature=0.5,
model_id="facebook/bart-large-cnn", # Modelo de resumen
custom_role_conversions=None,
)
@tool
def save_scraped_data_as_markdown(scraped_data: dict, filename: str = None) -> str:
"""Convierte el contenido scrapeado en un archivo Markdown mejor estructurado.
Mejoras:
- Resumen automático del contenido con NLP.
- Uso de encabezados, listas y negritas en Markdown.
- Guardado con timestamp para evitar sobrescribir archivos.
Args:
scraped_data: Diccionario con la URL y los datos extraídos.
filename: Nombre del archivo de salida (si no se da, se genera con timestamp).
Returns:
Mensaje de confirmación o error.
"""
try:
url = scraped_data.get("url", "Desconocido")
content_list = scraped_data.get("scraped_data", [])
if not content_list:
return "No hay datos para guardar en Markdown."
# Tokenizar en oraciones
tokenized_sentences = [sent_tokenize(text) for text in content_list]
formatted_content = "\n\n".join([" ".join(sentences) for sentences in tokenized_sentences])
# Hacer resumen del contenido (limitamos a 1024 tokens por si el texto es muy largo)
if len(formatted_content.split()) > 100:
summarized_text = model.query(
prompt=f"Resume el siguiente texto:\n\n{formatted_content[:1024]}",
max_length=150,
min_length=50,
)
else:
summarized_text = formatted_content
# Mejorar la estructura Markdown
markdown_content = f"# Contenido extraído de {url}\n\n"
markdown_content += f"## Resumen\n\n> {summarized_text}\n\n"
markdown_content += "## Contenido Completo\n\n"
for paragraph in formatted_content.split("\n\n"):
if len(paragraph.split()) > 10: # Si el párrafo es largo, lo tratamos como sección
markdown_content += f"### {paragraph[:50]}...\n\n{paragraph}\n\n"
else:
markdown_content += f"- **{paragraph}**\n\n"
# Generar nombre con timestamp si no se proporciona
if not filename:
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"scraped_{timestamp}.md"
# Guardar en un archivo Markdown
with open(filename, "w", encoding="utf-8") as file:
file.write(markdown_content)
return f"El contenido scrapeado se ha guardado en {filename}"
except Exception as e:
return f"Error al generar el archivo Markdown: {str(e)}"
@tool
def scrape_webpage(url: str, tag: str = "p", class_name: str = None) -> dict:
"""Extrae contenido de una página web según una etiqueta HTML y clase opcional.
Args:
url: URL de la página a scrapear.
tag: Etiqueta HTML a extraer (por defecto <p>).
class_name: Clase CSS opcional para filtrar resultados.
Returns:
Un diccionario con el contenido extraído.
"""
try:
headers = {"User-Agent": "Mozilla/5.0"}
response = requests.get(url, headers=headers)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
if class_name:
elements = soup.find_all(tag, class_=class_name)
else:
elements = soup.find_all(tag)
extracted_data = [element.get_text(strip=True) for element in elements]
return {"url": url, "scraped_data": extracted_data[:20]} # Limita a 20 resultados
except requests.exceptions.RequestException as e:
return {"error": f"Error al acceder a la URL: {str(e)}"}
except Exception as e:
return {"error": f"Error inesperado: {str(e)}"}
@tool
def extract_metadata_from_url(url: str) -> dict:
"""Extrae todos los metadatos de una página web.
Args:
url: La URL de la página web a analizar.
Returns:
Un diccionario con los metadatos encontrados.
"""
try:
headers = {"User-Agent": "Mozilla/5.0"}
response = requests.get(url, headers=headers)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
metadata = {}
for meta in soup.find_all("meta"):
if "name" in meta.attrs and "content" in meta.attrs:
metadata[meta["name"]] = meta["content"]
elif "property" in meta.attrs and "content" in meta.attrs:
metadata[meta["property"]] = meta["content"]
return metadata if metadata else {"error": "No se encontraron metadatos en la página."}
except requests.exceptions.RequestException as e:
return {"error": f"Error al acceder a la URL: {str(e)}"}
@tool
def get_current_time_in_timezone(timezone: str) -> str:
"""Devuelve la hora actual en una zona horaria específica.
Args:
timezone: Una cadena que representa una zona horaria válida (ej. 'America/New_York').
Returns:
La hora local actual en la zona horaria especificada.
"""
try:
tz = pytz.timezone(timezone)
local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
return f"La hora local actual en {timezone} es: {local_time}"
except Exception as e:
return f"Error obteniendo la hora para la zona horaria '{timezone}': {str(e)}"
final_answer = FinalAnswerTool()
# Import tool from Hub
image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True)
with open("prompts.yaml", "r") as stream:
prompt_templates = yaml.safe_load(stream)
agent = CodeAgent(
model=model,
tools=[
final_answer,
extract_metadata_from_url,
scrape_webpage,
save_scraped_data_as_markdown, # Se añade la nueva herramienta al agente
],
max_steps=6,
verbosity_level=1,
grammar=None,
planning_interval=None,
name=None,
description=None,
prompt_templates=prompt_templates,
)
GradioUI(agent).launch()