SEO / app.py
Merlintxu's picture
Update app.py
08b832d verified
raw
history blame
6.4 kB
import gradio as gr
import json
from seo_analyzer import SEOSpaceAnalyzer
import spacy
import subprocess
import sys
import logging
import os
from pathlib import Path
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def setup_spacy_model() -> None:
"""
Verifica y descarga el modelo spaCy 'es_core_news_lg' si no está instalado.
"""
try:
spacy.load("es_core_news_lg")
logger.info("Modelo spaCy 'es_core_news_lg' cargado correctamente.")
except OSError:
logger.info("Descargando modelo spaCy 'es_core_news_lg'...")
try:
subprocess.run(
[sys.executable, "-m", "spacy", "download", "es_core_news_lg"],
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
logger.info("Modelo descargado exitosamente.")
except subprocess.CalledProcessError as e:
logger.error(f"Error al descargar modelo: {e.stderr.decode()}")
raise RuntimeError("No se pudo descargar el modelo spaCy") from e
def list_content_storage_files() -> list:
"""
Busca todos los archivos dentro de la carpeta content_storage y
devuelve una lista de rutas relativas.
"""
base_dir = Path("content_storage")
if not base_dir.exists():
return []
file_list = [str(file.relative_to(base_dir)) for file in base_dir.glob("**/*") if file.is_file()]
logger.info(f"Archivos encontrados en content_storage: {file_list}")
return file_list
def download_storage_file(selected_file: str) -> str:
"""
Dado el nombre de un archivo (ruta relativa respecto a content_storage),
devuelve la ruta completa del archivo para descargarlo.
"""
if not selected_file:
return ""
file_path = Path("content_storage") / selected_file
if file_path.exists():
return str(file_path)
else:
return ""
def refresh_file_list() -> list:
"""Función para actualizar la lista de archivos en content_storage."""
return list_content_storage_files()
def create_interface() -> gr.Blocks:
analyzer = SEOSpaceAnalyzer()
with gr.Blocks(title="SEO Analyzer Pro", theme=gr.themes.Soft()) as interface:
gr.Markdown("""
# 🕵️ SEO Analyzer Pro
**Analizador SEO avanzado con modelos de lenguaje**
Ingresa la URL de un sitemap.xml para analizar el sitio web.
""")
with gr.Row():
with gr.Column():
sitemap_input = gr.Textbox(
label="URL del Sitemap",
placeholder="https://ejemplo.com/sitemap.xml",
interactive=True
)
analyze_btn = gr.Button("Analizar Sitio", variant="primary")
with gr.Row():
clear_btn = gr.Button("Limpiar")
download_btn = gr.Button("Descargar Reporte", variant="secondary")
plot_btn = gr.Button("Visualizar Enlaces Internos", variant="secondary")
with gr.Column():
status_output = gr.Textbox(label="Estado del Análisis", interactive=False)
with gr.Tabs():
with gr.Tab("📊 Resumen"):
stats_output = gr.JSON(label="Estadísticas Generales")
recommendations_output = gr.JSON(label="Recomendaciones SEO")
with gr.Tab("📝 Contenido"):
content_output = gr.JSON(label="Análisis de Contenido")
with gr.Tab("🔗 Enlaces"):
links_output = gr.JSON(label="Análisis de Enlaces")
links_plot = gr.Plot(label="Visualización de Enlaces Internos")
with gr.Tab("📄 Detalles"):
details_output = gr.JSON(label="Detalles Individuales")
with gr.Tab("📁 Archivos"):
file_dropdown = gr.Dropdown(label="Archivos en content_storage", choices=list_content_storage_files())
refresh_btn = gr.Button("Actualizar lista")
download_file_btn = gr.Button("Descargar Archivo Seleccionado", variant="secondary")
file_download = gr.File(label="Archivo Seleccionado")
def generate_report() -> str:
"""
Genera un informe en formato JSON con el análisis SEO y lo guarda en content_storage.
Retorna la ruta del archivo generado.
"""
if analyzer.current_analysis:
report_path = "content_storage/seo_report.json"
try:
with open(report_path, 'w', encoding='utf-8') as f:
json.dump(analyzer.current_analysis, f, indent=2, ensure_ascii=False)
logger.info(f"Reporte generado en: {report_path}")
return report_path
except Exception as e:
logger.error(f"Error generando reporte: {e}")
return ""
else:
logger.warning("No hay análisis para generar el reporte.")
return ""
def plot_internal_links(links_json: dict) -> any:
return analyzer.plot_internal_links(links_json)
analyze_btn.click(
fn=analyzer.analyze_sitemap,
inputs=sitemap_input,
outputs=[stats_output, recommendations_output, content_output, links_output, details_output],
show_progress=True
)
clear_btn.click(
fn=lambda: [None, None, None, None, None],
outputs=[stats_output, recommendations_output, content_output, links_output, details_output]
)
# Se elimina el parámetro _js para evitar el error.
download_btn.click(
fn=generate_report,
outputs=file_download
)
plot_btn.click(
fn=plot_internal_links,
inputs=links_output,
outputs=links_plot
)
refresh_btn.click(
fn=refresh_file_list,
outputs=file_dropdown
)
download_file_btn.click(
fn=download_storage_file,
inputs=file_dropdown,
outputs=file_download
)
return interface
if __name__ == "__main__":
setup_spacy_model()
app = create_interface()
app.launch(server_name="0.0.0.0", server_port=7860, show_error=True, share=False)