File size: 6,398 Bytes
a8a2139 dcf8a98 a8a2139 8b7112a a8a2139 90799a0 63fe26b a8a2139 dcf8a98 a8a2139 bb43f76 3971861 bb43f76 a8a2139 63fe26b a8a2139 bb43f76 90799a0 3971861 90799a0 3971861 90799a0 3971861 90799a0 3971861 90799a0 bb43f76 7d39cf2 63fe26b 3969e8a a8a2139 63fe26b 7d39cf2 63fe26b a8a2139 3971861 a8a2139 3969e8a bb43f76 63fe26b 3969e8a 63fe26b 3969e8a bb43f76 a8a2139 90799a0 a8a2139 3971861 d3a54e9 3971861 bb43f76 3971861 a8a2139 7d39cf2 3969e8a a8a2139 3969e8a a8a2139 3969e8a c4827cf 3969e8a 6c55771 c4827cf dcf8a98 bb43f76 a8a2139 bb43f76 90799a0 7d39cf2 bb43f76 c561b6f 63fe26b a8a2139 08b832d |
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 |
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)
|