SEO / app.py
Merlintxu's picture
Update app.py
f415fc9 verified
raw
history blame
5.04 kB
import gradio as gr
import json
import pandas as pd
import spacy
import subprocess
import sys
import logging
from pathlib import Path
from seo_analyzer import SEOSpaceAnalyzer
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def setup_spacy_model():
"""Carga o descarga el modelo spaCy necesario."""
try:
spacy.load("es_core_news_lg")
except OSError:
logger.info("Descargando spaCy model es_core_news_lg...")
subprocess.run([sys.executable, "-m", "spacy", "download", "es_core_news_lg"], check=True)
def create_interface() -> gr.Blocks:
analyzer = SEOSpaceAnalyzer()
with gr.Blocks(title="SEO Analyzer Pro", theme=gr.themes.Soft()) as demo:
gr.Markdown("""
# 🧠 SEO Analyzer Pro
Este espacio analiza contenido web orientado a normativa bancaria y genera:
- Temas inferidos automáticamente
- Títulos y meta descripciones SEO
- Alertas por lenguaje de riesgo
""")
with gr.Row():
sitemap_input = gr.Textbox(label="📍 URL del Sitemap", placeholder="https://ejemplo.com/sitemap.xml")
analyze_btn = gr.Button("🔍 Analizar")
clear_btn = gr.Button("🧹 Limpiar")
download_json_btn = gr.Button("📥 Descargar JSON")
download_csv_btn = gr.Button("📤 Descargar CSV")
status_output = gr.Textbox(label="Estado del análisis")
with gr.Tabs():
with gr.Tab("📊 Resumen"):
stats_output = gr.JSON(label="Estadísticas")
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 por página")
with gr.Tab("🧠 SEO y Temas"):
seo_tags_output = gr.JSON(label="Metadatos SEO generados")
topics_output = gr.JSON(label="Temas inferidos")
flags_output = gr.JSON(label="Términos prohibidos detectados")
with gr.Tab("🔗 Similitud"):
similarity_output = gr.JSON(label="Similitud entre URLs")
def analyze_with_status(sitemap_url):
try:
result = analyzer.analyze_sitemap(sitemap_url)
return (*result, "✅ Análisis completado")
except Exception as e:
return [None]*8 + [f"❌ Error: {e}"]
def export_json():
if analyzer.current_analysis:
path = Path("content_storage/seo_report.json")
with open(path, "w", encoding="utf-8") as f:
json.dump(analyzer.current_analysis, f, ensure_ascii=False, indent=2)
return str(path)
return ""
def export_csv():
if not analyzer.current_analysis:
return ""
path = Path("content_storage/seo_summary.csv")
data = []
for url, seo in analyzer.current_analysis.get("seo_tags", {}).items():
data.append({
"url": url,
"title": seo.get("title", ""),
"meta_description": seo.get("meta_description", ""),
"flags": ", ".join(seo.get("flags", [])),
"topics": ", ".join(analyzer.current_analysis.get("topics", {}).get(url, [])),
"summary": analyzer.current_analysis.get("summaries", {}).get(url, "")
})
pd.DataFrame(data).to_csv(path, index=False)
return str(path)
analyze_btn.click(
fn=analyze_with_status,
inputs=sitemap_input,
outputs=[
stats_output, recommendations_output, content_output,
links_output, details_output, similarity_output,
seo_tags_output, status_output
]
)
clear_btn.click(fn=lambda: [None]*8, outputs=[
stats_output, recommendations_output, content_output,
links_output, details_output, similarity_output,
seo_tags_output, status_output
])
download_json_btn.click(fn=export_json, outputs=status_output)
download_csv_btn.click(fn=export_csv, outputs=status_output)
links_output.change(fn=analyzer.plot_internal_links, inputs=links_output, outputs=links_plot)
seo_tags_output.change(fn=lambda: analyzer.current_analysis.get("topics", {}), outputs=topics_output)
seo_tags_output.change(fn=lambda: analyzer.current_analysis.get("flags", {}), outputs=flags_output)
return demo
if __name__ == "__main__":
setup_spacy_model()
app = create_interface()
app.launch(server_name="0.0.0.0", server_port=7860)