Merlintxu commited on
Commit
2e8fa9d
·
verified ·
1 Parent(s): c2b829f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +54 -20
app.py CHANGED
@@ -15,13 +15,52 @@ def setup_spacy_model():
15
  """Carga o descarga el modelo spaCy necesario."""
16
  try:
17
  spacy.load("es_core_news_lg")
 
18
  except OSError:
19
  logger.info("Descargando spaCy model es_core_news_lg...")
20
  subprocess.run([sys.executable, "-m", "spacy", "download", "es_core_news_lg"], check=True)
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  def create_interface() -> gr.Blocks:
23
  analyzer = SEOSpaceAnalyzer()
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  with gr.Blocks(title="SEO Analyzer Pro", theme=gr.themes.Soft()) as demo:
26
  gr.Markdown("""
27
  # 🧠 SEO Analyzer Pro
@@ -30,16 +69,13 @@ def create_interface() -> gr.Blocks:
30
  - Títulos y meta descripciones SEO
31
  - Alertas por lenguaje de riesgo
32
  """)
33
-
34
  with gr.Row():
35
  sitemap_input = gr.Textbox(label="📍 URL del Sitemap", placeholder="https://ejemplo.com/sitemap.xml")
36
  analyze_btn = gr.Button("🔍 Analizar")
37
  clear_btn = gr.Button("🧹 Limpiar")
38
  download_json_btn = gr.Button("📥 Descargar JSON")
39
  download_csv_btn = gr.Button("📤 Descargar CSV")
40
-
41
- status_output = gr.Textbox(label="Estado del análisis")
42
-
43
  with gr.Tabs():
44
  with gr.Tab("📊 Resumen"):
45
  stats_output = gr.JSON(label="Estadísticas")
@@ -53,27 +89,24 @@ def create_interface() -> gr.Blocks:
53
  details_output = gr.JSON(label="Detalles por página")
54
  with gr.Tab("🧠 SEO y Temas"):
55
  seo_tags_output = gr.JSON(label="Metadatos SEO generados")
 
56
  topics_output = gr.JSON(label="Temas inferidos")
57
  flags_output = gr.JSON(label="Términos prohibidos detectados")
58
  with gr.Tab("🔗 Similitud"):
59
  similarity_output = gr.JSON(label="Similitud entre URLs")
60
-
61
- def analyze_with_status(sitemap_url):
62
- try:
63
- result = analyzer.analyze_sitemap(sitemap_url)
64
- return (*result, " Análisis completado")
65
- except Exception as e:
66
- return [None]*8 + [f"❌ Error: {e}"]
67
-
68
- def export_json():
69
  if analyzer.current_analysis:
70
  path = Path("content_storage/seo_report.json")
71
  with open(path, "w", encoding="utf-8") as f:
72
- json.dump(analyzer.current_analysis, f, ensure_ascii=False, indent=2)
73
  return str(path)
74
  return ""
75
-
76
- def export_csv():
77
  if not analyzer.current_analysis:
78
  return ""
79
  path = Path("content_storage/seo_summary.csv")
@@ -89,15 +122,15 @@ def create_interface() -> gr.Blocks:
89
  })
90
  pd.DataFrame(data).to_csv(path, index=False)
91
  return str(path)
92
-
93
  analyze_btn.click(
94
- fn=analyze_with_status,
95
  inputs=sitemap_input,
96
  outputs=[
97
  stats_output, recommendations_output, content_output,
98
  links_output, details_output, similarity_output,
99
  seo_tags_output, status_output
100
- ]
 
101
  )
102
  clear_btn.click(fn=lambda: [None]*8, outputs=[
103
  stats_output, recommendations_output, content_output,
@@ -109,7 +142,8 @@ def create_interface() -> gr.Blocks:
109
  links_output.change(fn=analyzer.plot_internal_links, inputs=links_output, outputs=links_plot)
110
  seo_tags_output.change(fn=lambda: analyzer.current_analysis.get("topics", {}), outputs=topics_output)
111
  seo_tags_output.change(fn=lambda: analyzer.current_analysis.get("flags", {}), outputs=flags_output)
112
-
 
113
  return demo
114
 
115
  if __name__ == "__main__":
 
15
  """Carga o descarga el modelo spaCy necesario."""
16
  try:
17
  spacy.load("es_core_news_lg")
18
+ logger.info("Modelo spaCy 'es_core_news_lg' cargado correctamente.")
19
  except OSError:
20
  logger.info("Descargando spaCy model es_core_news_lg...")
21
  subprocess.run([sys.executable, "-m", "spacy", "download", "es_core_news_lg"], check=True)
22
 
23
+ def list_content_storage_files() -> list:
24
+ """Devuelve la lista de archivos en la carpeta content_storage."""
25
+ base_dir = Path("content_storage")
26
+ if not base_dir.exists():
27
+ return []
28
+ return [str(file.relative_to(base_dir)) for file in base_dir.glob("**/*") if file.is_file()]
29
+
30
+ def download_storage_file(selected_file: str) -> str:
31
+ """Dado el nombre del archivo (relativo a content_storage), devuelve la ruta para descarga."""
32
+ if not selected_file:
33
+ return ""
34
+ file_path = Path("content_storage") / selected_file
35
+ return str(file_path) if file_path.exists() else ""
36
+
37
+ def refresh_file_list() -> list:
38
+ """Actualiza la lista de archivos disponibles en content_storage."""
39
+ return list_content_storage_files()
40
+
41
+ # Creamos la interfaz
42
  def create_interface() -> gr.Blocks:
43
  analyzer = SEOSpaceAnalyzer()
44
 
45
+ # Definimos una función envoltorio para incluir callbacks de estado
46
+ def analyze_with_callbacks(sitemap_url: str):
47
+ status_msgs = []
48
+
49
+ def status_callback(msg: str):
50
+ status_msgs.append(msg)
51
+ logger.info(msg)
52
+
53
+ def progress_callback(current: int, total: int):
54
+ logger.info(f"Batch {current} de {total} procesado.")
55
+
56
+ # Se llama al método modificado que procesa en lotes de 5
57
+ results = analyzer.analyze_sitemap(sitemap_url, progress_callback=progress_callback, status_callback=status_callback)
58
+ final_status = "\n".join(status_msgs) if status_msgs else "Análisis completado."
59
+ # 'results' es una tupla de 7 elementos:
60
+ # (stats, recommendations, content_analysis, links, details, similarities, seo_tags)
61
+ # Devolvemos esos 7 outputs más el mensaje final en estado (total 8)
62
+ return (*results, final_status)
63
+
64
  with gr.Blocks(title="SEO Analyzer Pro", theme=gr.themes.Soft()) as demo:
65
  gr.Markdown("""
66
  # 🧠 SEO Analyzer Pro
 
69
  - Títulos y meta descripciones SEO
70
  - Alertas por lenguaje de riesgo
71
  """)
 
72
  with gr.Row():
73
  sitemap_input = gr.Textbox(label="📍 URL del Sitemap", placeholder="https://ejemplo.com/sitemap.xml")
74
  analyze_btn = gr.Button("🔍 Analizar")
75
  clear_btn = gr.Button("🧹 Limpiar")
76
  download_json_btn = gr.Button("📥 Descargar JSON")
77
  download_csv_btn = gr.Button("📤 Descargar CSV")
78
+ status_output = gr.Textbox(label="Estado del análisis", interactive=False)
 
 
79
  with gr.Tabs():
80
  with gr.Tab("📊 Resumen"):
81
  stats_output = gr.JSON(label="Estadísticas")
 
89
  details_output = gr.JSON(label="Detalles por página")
90
  with gr.Tab("🧠 SEO y Temas"):
91
  seo_tags_output = gr.JSON(label="Metadatos SEO generados")
92
+ # Los siguientes se actualizan vía change en seo_tags_output
93
  topics_output = gr.JSON(label="Temas inferidos")
94
  flags_output = gr.JSON(label="Términos prohibidos detectados")
95
  with gr.Tab("🔗 Similitud"):
96
  similarity_output = gr.JSON(label="Similitud entre URLs")
97
+ with gr.Tab("📁 Archivos"):
98
+ file_dropdown = gr.Dropdown(label="Archivos en content_storage", choices=list_content_storage_files())
99
+ refresh_btn = gr.Button("Actualizar lista")
100
+ download_file_btn = gr.Button("Descargar Archivo Seleccionado", variant="secondary")
101
+ file_download = gr.File(label="Archivo Seleccionado")
102
+ def export_json() -> str:
 
 
 
103
  if analyzer.current_analysis:
104
  path = Path("content_storage/seo_report.json")
105
  with open(path, "w", encoding="utf-8") as f:
106
+ json.dump(analyzer.current_analysis, f, indent=2, ensure_ascii=False)
107
  return str(path)
108
  return ""
109
+ def export_csv() -> str:
 
110
  if not analyzer.current_analysis:
111
  return ""
112
  path = Path("content_storage/seo_summary.csv")
 
122
  })
123
  pd.DataFrame(data).to_csv(path, index=False)
124
  return str(path)
 
125
  analyze_btn.click(
126
+ fn=analyze_with_callbacks,
127
  inputs=sitemap_input,
128
  outputs=[
129
  stats_output, recommendations_output, content_output,
130
  links_output, details_output, similarity_output,
131
  seo_tags_output, status_output
132
+ ],
133
+ show_progress=True
134
  )
135
  clear_btn.click(fn=lambda: [None]*8, outputs=[
136
  stats_output, recommendations_output, content_output,
 
142
  links_output.change(fn=analyzer.plot_internal_links, inputs=links_output, outputs=links_plot)
143
  seo_tags_output.change(fn=lambda: analyzer.current_analysis.get("topics", {}), outputs=topics_output)
144
  seo_tags_output.change(fn=lambda: analyzer.current_analysis.get("flags", {}), outputs=flags_output)
145
+ refresh_btn.click(fn=refresh_file_list, outputs=file_dropdown)
146
+ download_file_btn.click(fn=download_storage_file, inputs=file_dropdown, outputs=file_download)
147
  return demo
148
 
149
  if __name__ == "__main__":