Spaces:
Running
Running
Download app.py from djzero2/luchitochavez: direct link, hf CLI and curl.
- Browser
- Download file 6.41 kB
-
https://huggingface.co/spaces/djzero2/luchitochavez/resolve/main/app.py
- Command line
-
hf download hf://spaces/djzero2/luchitochavez/app.py
-
curl -L -o app.py https://huggingface.co/spaces/djzero2/luchitochavez/resolve/main/app.py
6.41 kB
| import gradio as gr | |
| import requests | |
| from newspaper import Article | |
| import base64 | |
| def extraer_info(url): | |
| if not url.strip(): | |
| return "[Error]: Por favor, ingresa una URL válida.", "<p>Sin imagen</p>" | |
| try: | |
| # Cabeceras simulando un navegador real para el HTML de la noticia | |
| headers = { | |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", | |
| "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", | |
| "Accept-Language": "es-ES,es;q=0.9", | |
| "Referer": "https://www.google.com/" | |
| } | |
| # Descargamos el HTML de la noticia | |
| response = requests.get(url, headers=headers, timeout=15) | |
| if response.status_code != 200: | |
| return f"[Error del Servidor Web]: El sitio respondió con código {response.status_code}. Bloqueo Anti-Bot activo.", "<p>No se pudo cargar la noticia debido al bloqueo del sitio web.</p>" | |
| # Procesamos con newspaper3k | |
| articulo = Article(url, language='es') | |
| articulo.set_html(response.text) | |
| articulo.parse() | |
| titulo_y_texto = f"TÍTULO: {articulo.title}\n\n{articulo.text}" | |
| # --- BLOQUE SEGURO DE DESCARGA DE IMAGEN --- | |
| html_imagen = "" | |
| if articulo.top_image: | |
| try: | |
| # Modificamos el Referer para que parezca que estamos viendo la imagen desde el propio periódico | |
| headers_imagen = headers.copy() | |
| headers_imagen["Referer"] = url | |
| # Intentamos descargar la imagen | |
| img_response = requests.get(articulo.top_image, headers=headers_imagen, timeout=10) | |
| if img_response.status_code == 200: | |
| content_type = img_response.headers.get('content-type', 'image/jpeg') | |
| encoded_img = base64.b64encode(img_response.content).decode('utf-8') | |
| # --- SOLUCIÓN VISUAL PARA INTEGRACIÓN EN PANTALLA DE INICIO (iOS) --- | |
| html_imagen = f""" | |
| <div style="text-align: center;"> | |
| <p style="color: #6b7280; font-size: 13px; margin-bottom: 8px; font-weight: 500;"> | |
| 📱 En iPhone: Mantén presionada la imagen para guardarla en tus Fotos | |
| </p> | |
| <img src="data:{content_type};base64,{encoded_img}" style="max-width:100%; height:auto; border-radius:8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);" alt="Imagen de la noticia"> | |
| </div> | |
| """ | |
| else: | |
| # Si da 403 o cualquier otro error, NO rompemos la app, damos una alternativa | |
| html_imagen = f""" | |
| <div style='border: 1px dashed #ef4444; padding: 10px; border-radius: 8px; text-align: center;'> | |
| <p style='color:#ef4444; margin: 0; font-weight: bold;'>⚠️ Error {img_response.status_code} al descargar imagen</p> | |
| <p style='color:gray; font-size: 12px; margin: 5px 0 0 0;'>El servidor de la noticia bloqueó la descarga automatizada de la imagen, pero el texto se extrajo con éxito.</p> | |
| </div> | |
| """ | |
| except Exception as e: | |
| # Si hay timeout o error de conexión en la imagen, la app sigue viva | |
| html_imagen = f"<p style='color:orange;'>⚠️ No se pudo previsualizar la imagen (Error de conexión).</p>" | |
| else: | |
| html_imagen = "<p style='color:gray;'>Este artículo no contiene una imagen principal.</p>" | |
| return titulo_y_texto, html_imagen | |
| except Exception as e: | |
| # Este catch solo atrapa errores graves del procesamiento de texto | |
| return f"[Error al extraer la información]: {str(e)}", "<p style='color:red;'>Error crítico en el proceso</p>" | |
| # Interfaz Gráfica con gr.Blocks | |
| with gr.Blocks(title="Extractor de Noticias") as demo: | |
| gr.Markdown("## 📰 Extractor de Texto e Imagen de Noticias") | |
| gr.Markdown("Pega el enlace de un artículo para obtener su contenido limpio y la imagen principal.") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| url_input = gr.Textbox( | |
| label="URL de la noticia", | |
| placeholder="https://ejemplo.com/noticia", | |
| lines=1 | |
| ) | |
| btn_extraer = gr.Button("🚀 Extraer Contenido", variant="primary") | |
| gr.HTML(""" | |
| <button id="btn_copiar" style=" | |
| width: 100%; | |
| background-color: #2563eb; | |
| color: white; | |
| padding: 10px; | |
| border: none; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| font-weight: bold; | |
| margin-top: 10px; | |
| " onclick=" | |
| const txt = document.querySelector('#texto_extraido textarea'); | |
| if (txt && txt.value) { | |
| navigator.clipboard.writeText(txt.value).then(() => { | |
| const btn = document.getElementById('btn_copiar'); | |
| const original = btn.innerHTML; | |
| btn.innerHTML = '✔️ ¡Copiado!'; | |
| btn.style.backgroundColor = '#16a34a'; | |
| setTimeout(() => { | |
| btn.innerHTML = original; | |
| btn.style.backgroundColor = '#2563eb'; | |
| }, 2000); | |
| }); | |
| } else { | |
| alert('No hay texto para copiar'); | |
| } | |
| ">📋 Copiar texto extraído</button> | |
| """) | |
| with gr.Column(scale=3): | |
| gr.Markdown("### Imagen principal") | |
| imagen_output = gr.HTML(value="<p style='color:gray;'>La imagen aparecerá aquí...</p>") | |
| texto_output = gr.Textbox( | |
| label="Texto e información extraída", | |
| lines=12, | |
| interactive=False, | |
| elem_id="texto_extraido" | |
| ) | |
| btn_extraer.click( | |
| fn=extraer_info, | |
| inputs=[url_input], | |
| outputs=[texto_output, imagen_output] | |
| ) | |
| demo.launch() |