Merlintxu commited on
Commit
f415fc9
·
verified ·
1 Parent(s): 92809de

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -169
app.py CHANGED
@@ -1,204 +1,118 @@
1
- Hugging Face's logo
2
- Hugging Face
3
- Models
4
- Datasets
5
- Spaces
6
- Posts
7
- Docs
8
- Enterprise
9
- Pricing
10
-
11
-
12
-
13
- Spaces:
14
-
15
- Merlintxu
16
- /
17
- SEO
18
-
19
-
20
- like
21
- 0
22
-
23
- App
24
- Files
25
- Community
26
- Settings
27
- SEO
28
- /
29
- app.py
30
-
31
- Merlintxu's picture
32
- Merlintxu
33
- Update app.py
34
- 08b832d
35
- verified
36
- about 7 hours ago
37
- raw
38
-
39
- Copy download link
40
- history
41
- blame
42
- edit
43
- delete
44
-
45
- 6.4 kB
46
  import gradio as gr
47
  import json
48
- from seo_analyzer import SEOSpaceAnalyzer
49
  import spacy
50
  import subprocess
51
  import sys
52
  import logging
53
- import os
54
  from pathlib import Path
 
55
 
56
  logging.basicConfig(level=logging.INFO)
57
  logger = logging.getLogger(__name__)
58
 
59
- def setup_spacy_model() -> None:
60
- """
61
- Verifica y descarga el modelo spaCy 'es_core_news_lg' si no está instalado.
62
- """
63
  try:
64
  spacy.load("es_core_news_lg")
65
- logger.info("Modelo spaCy 'es_core_news_lg' cargado correctamente.")
66
  except OSError:
67
- logger.info("Descargando modelo spaCy 'es_core_news_lg'...")
68
- try:
69
- subprocess.run(
70
- [sys.executable, "-m", "spacy", "download", "es_core_news_lg"],
71
- check=True,
72
- stdout=subprocess.PIPE,
73
- stderr=subprocess.PIPE
74
- )
75
- logger.info("Modelo descargado exitosamente.")
76
- except subprocess.CalledProcessError as e:
77
- logger.error(f"Error al descargar modelo: {e.stderr.decode()}")
78
- raise RuntimeError("No se pudo descargar el modelo spaCy") from e
79
-
80
- def list_content_storage_files() -> list:
81
- """
82
- Busca todos los archivos dentro de la carpeta content_storage y
83
- devuelve una lista de rutas relativas.
84
- """
85
- base_dir = Path("content_storage")
86
- if not base_dir.exists():
87
- return []
88
- file_list = [str(file.relative_to(base_dir)) for file in base_dir.glob("**/*") if file.is_file()]
89
- logger.info(f"Archivos encontrados en content_storage: {file_list}")
90
- return file_list
91
-
92
- def download_storage_file(selected_file: str) -> str:
93
- """
94
- Dado el nombre de un archivo (ruta relativa respecto a content_storage),
95
- devuelve la ruta completa del archivo para descargarlo.
96
- """
97
- if not selected_file:
98
- return ""
99
- file_path = Path("content_storage") / selected_file
100
- if file_path.exists():
101
- return str(file_path)
102
- else:
103
- return ""
104
-
105
- def refresh_file_list() -> list:
106
- """Función para actualizar la lista de archivos en content_storage."""
107
- return list_content_storage_files()
108
 
109
  def create_interface() -> gr.Blocks:
110
  analyzer = SEOSpaceAnalyzer()
111
- with gr.Blocks(title="SEO Analyzer Pro", theme=gr.themes.Soft()) as interface:
 
112
  gr.Markdown("""
113
- # 🕵️ SEO Analyzer Pro
114
- **Analizador SEO avanzado con modelos de lenguaje**
115
-
116
- Ingresa la URL de un sitemap.xml para analizar el sitio web.
 
117
  """)
 
118
  with gr.Row():
119
- with gr.Column():
120
- sitemap_input = gr.Textbox(
121
- label="URL del Sitemap",
122
- placeholder="https://ejemplo.com/sitemap.xml",
123
- interactive=True
124
- )
125
- analyze_btn = gr.Button("Analizar Sitio", variant="primary")
126
- with gr.Row():
127
- clear_btn = gr.Button("Limpiar")
128
- download_btn = gr.Button("Descargar Reporte", variant="secondary")
129
- plot_btn = gr.Button("Visualizar Enlaces Internos", variant="secondary")
130
- with gr.Column():
131
- status_output = gr.Textbox(label="Estado del Análisis", interactive=False)
132
  with gr.Tabs():
133
  with gr.Tab("📊 Resumen"):
134
- stats_output = gr.JSON(label="Estadísticas Generales")
135
  recommendations_output = gr.JSON(label="Recomendaciones SEO")
136
  with gr.Tab("📝 Contenido"):
137
- content_output = gr.JSON(label="Análisis de Contenido")
138
  with gr.Tab("🔗 Enlaces"):
139
- links_output = gr.JSON(label="Análisis de Enlaces")
140
- links_plot = gr.Plot(label="Visualización de Enlaces Internos")
141
  with gr.Tab("📄 Detalles"):
142
- details_output = gr.JSON(label="Detalles Individuales")
143
- with gr.Tab("📁 Archivos"):
144
- file_dropdown = gr.Dropdown(label="Archivos en content_storage", choices=list_content_storage_files())
145
- refresh_btn = gr.Button("Actualizar lista")
146
- download_file_btn = gr.Button("Descargar Archivo Seleccionado", variant="secondary")
147
- file_download = gr.File(label="Archivo Seleccionado")
148
- def generate_report() -> str:
149
- """
150
- Genera un informe en formato JSON con el análisis SEO y lo guarda en content_storage.
151
- Retorna la ruta del archivo generado.
152
- """
 
 
 
 
 
153
  if analyzer.current_analysis:
154
- report_path = "content_storage/seo_report.json"
155
- try:
156
- with open(report_path, 'w', encoding='utf-8') as f:
157
- json.dump(analyzer.current_analysis, f, indent=2, ensure_ascii=False)
158
- logger.info(f"Reporte generado en: {report_path}")
159
- return report_path
160
- except Exception as e:
161
- logger.error(f"Error generando reporte: {e}")
162
- return ""
163
- else:
164
- logger.warning("No hay análisis para generar el reporte.")
165
  return ""
166
- def plot_internal_links(links_json: dict) -> any:
167
- return analyzer.plot_internal_links(links_json)
 
 
 
 
 
 
 
 
 
 
 
 
168
  analyze_btn.click(
169
- fn=analyzer.analyze_sitemap,
170
  inputs=sitemap_input,
171
- outputs=[stats_output, recommendations_output, content_output, links_output, details_output],
172
- show_progress=True
 
 
 
173
  )
174
- clear_btn.click(
175
- fn=lambda: [None, None, None, None, None],
176
- outputs=[stats_output, recommendations_output, content_output, links_output, details_output]
177
- )
178
- # Se elimina el parámetro _js para evitar el error.
179
- download_btn.click(
180
- fn=generate_report,
181
- outputs=file_download
182
- )
183
- plot_btn.click(
184
- fn=plot_internal_links,
185
- inputs=links_output,
186
- outputs=links_plot
187
- )
188
- refresh_btn.click(
189
- fn=refresh_file_list,
190
- outputs=file_dropdown
191
- )
192
- download_file_btn.click(
193
- fn=download_storage_file,
194
- inputs=file_dropdown,
195
- outputs=file_download
196
- )
197
- return interface
198
 
199
  if __name__ == "__main__":
200
  setup_spacy_model()
201
  app = create_interface()
202
- app.launch(server_name="0.0.0.0", server_port=7860, show_error=True, share=False)
203
-
204
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
  import json
3
+ import pandas as pd
4
  import spacy
5
  import subprocess
6
  import sys
7
  import logging
 
8
  from pathlib import Path
9
+ from seo_analyzer import SEOSpaceAnalyzer
10
 
11
  logging.basicConfig(level=logging.INFO)
12
  logger = logging.getLogger(__name__)
13
 
14
+ 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
28
+ Este espacio analiza contenido web orientado a normativa bancaria y genera:
29
+ - Temas inferidos automáticamente
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")
46
  recommendations_output = gr.JSON(label="Recomendaciones SEO")
47
  with gr.Tab("📝 Contenido"):
48
+ content_output = gr.JSON(label="Análisis de contenido")
49
  with gr.Tab("🔗 Enlaces"):
50
+ links_output = gr.JSON(label="Análisis de enlaces")
51
+ links_plot = gr.Plot(label="Visualización de enlaces internos")
52
  with gr.Tab("📄 Detalles"):
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")
80
+ data = []
81
+ for url, seo in analyzer.current_analysis.get("seo_tags", {}).items():
82
+ data.append({
83
+ "url": url,
84
+ "title": seo.get("title", ""),
85
+ "meta_description": seo.get("meta_description", ""),
86
+ "flags": ", ".join(seo.get("flags", [])),
87
+ "topics": ", ".join(analyzer.current_analysis.get("topics", {}).get(url, [])),
88
+ "summary": analyzer.current_analysis.get("summaries", {}).get(url, "")
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,
104
+ links_output, details_output, similarity_output,
105
+ seo_tags_output, status_output
106
+ ])
107
+ download_json_btn.click(fn=export_json, outputs=status_output)
108
+ download_csv_btn.click(fn=export_csv, outputs=status_output)
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__":
116
  setup_spacy_model()
117
  app = create_interface()
118
+ app.launch(server_name="0.0.0.0", server_port=7860)