Skip to content

Commit ffe2422

Browse files
committed
feat: improve news summary processing and update dependencies
1 parent 9d40e94 commit ffe2422

3 files changed

Lines changed: 48 additions & 22 deletions

File tree

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,10 @@ dev101_bot/
9999
|--------|-----------|
100100
| CyberSecurity News | Ciberseguridad / IA |
101101
| WeLiveSecurity (ESET) | Ciberseguridad |
102-
| Xataka | IA |
103-
| WIRED en Español | IA |
102+
| DragonJAR | Ciberseguridad |
103+
| El Lado Del Mal | Ciberseguridad |
104+
| IA en Español (Substack) | IA |
105+
| Xataka IA | IA |
104106

105107
---
106108

@@ -111,7 +113,9 @@ requests
111113
beautifulsoup4
112114
lxml
113115
groq
116+
httpx
114117
python-dotenv
118+
cloudscraper
115119
```
116120

117121
---

requirements.txt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
requests
2-
beautifulsoup4
3-
lxml
4-
groq
5-
python-dotenv
6-
cloudscraper
1+
requests==2.32.3
2+
beautifulsoup4==4.12.3
3+
lxml==6.0.4
4+
groq==1.2.0
5+
httpx==0.28.1
6+
python-dotenv==1.0.1
7+
cloudscraper==1.2.71

run_job.py

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ def get_published_links():
138138
return set()
139139
return {n.get("enlace_original", "") for n in noticias}
140140

141-
def push_to_github(item, summary_text, categoria):
141+
def push_to_github(item, titulo, resumen, categoria):
142142
token = GIT_TOKEN.strip()
143143
if not token:
144144
return
@@ -153,15 +153,14 @@ def push_to_github(item, summary_text, categoria):
153153
return
154154

155155
nuevo_id = (noticias[0]["id"] + 1) if noticias else 1
156-
lines = summary_text.split("\n")
157156
# Usar timezone-aware datetime
158157
ahora = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
159158
nueva = {
160159
"id": nuevo_id,
161160
"fecha": ahora,
162161
"categoria": categoria,
163-
"titulo": clean_markdown(lines[0].strip()),
164-
"resumen": clean_markdown("\n".join(lines[1:]).strip()),
162+
"titulo": titulo,
163+
"resumen": resumen,
165164
"url_imagen": get_image_url(categoria),
166165
"enlace_original": item["link"],
167166
"fuente": item["source"]
@@ -238,21 +237,39 @@ def get_image_url(categoria):
238237
def summarize_news(title, content):
239238
if not GROQ_API_KEY:
240239
logger.error("GROQ_API_KEY no configurada")
241-
return f"{title}\n(Resumen no disponible)"
240+
return None, None
242241
try:
243242
r = groq_client.chat.completions.create(
244243
model="llama-3.3-70b-versatile",
245244
messages=[
246-
{"role": "system", "content": "Eres un experto en IA y Ciberseguridad. Resume la noticia en un titular impactante y un resumen de máximo 2 frases en español. IMPORTANTE: Si la noticia NO trata sobre IA o Ciberseguridad de forma clara, responde ÚNICAMENTE con la palabra 'RECHAZAR'."},
247-
{"role": "user", "content": f"Título: {title}\nContenido: {content}"}
245+
{"role": "system", "content": "Eres un experto en IA y Ciberseguridad. Resume la noticia en un titular impactante y un resumen de máximo 2 frases en español. FORMATO DE RESPUESTA: Primera línea el título, segunda línea el resumen. NADA MÁS. Si la noticia NO trata sobre IA o Ciberseguridad de forma clara, responde ÚNICAMENTE con la palabra 'RECHAZAR'."},
246+
{"role": "user", "content": f"Título original: {title}\nContenido: {content}"}
248247
],
249248
temperature=0.3,
250249
max_tokens=150,
251250
)
252-
return r.choices[0].message.content.strip()
251+
response = r.choices[0].message.content.strip()
252+
253+
if "RECHAZAR" in response.upper():
254+
return "RECHAZAR", None
255+
256+
lines = [l.strip() for l in response.split("\n") if l.strip()]
257+
258+
if len(lines) >= 2:
259+
return clean_markdown(lines[0]), clean_markdown(" ".join(lines[1:]))
260+
261+
# Fallback: Si solo hay una línea, intentar separar por punto o dos puntos
262+
text = lines[0]
263+
match = re.search(r'[:.!?]\s', text)
264+
if match:
265+
idx = match.start() + 1
266+
return clean_markdown(text[:idx]), clean_markdown(text[idx:])
267+
268+
return clean_markdown(text), "" # Aún así devolvemos algo, el job validará si el resumen está vacío
269+
253270
except Exception as e:
254271
logger.error(f"Groq error: {e}")
255-
return f"{title}\n(Resumen no disponible)"
272+
return None, None
256273

257274
# ── Telegram ──────────────────────────────────────────────────────────────────
258275

@@ -407,17 +424,21 @@ def job():
407424
logger.info(f"Procesando: {item['title']}")
408425

409426
# Resumen y filtro de relevancia con Groq
410-
summary = summarize_news(item['title'], item.get('content', item['title']))
427+
titulo_ai, resumen_ai = summarize_news(item['title'], item.get('content', item['title']))
411428

412-
if "RECHAZAR" in summary.upper():
429+
if titulo_ai == "RECHAZAR":
413430
logger.info(f"Noticia rechazada por irrelevante: {item['title']}")
414431
continue
432+
433+
if not titulo_ai or not resumen_ai:
434+
logger.info(f"Noticia descartada por resumen incompleto: {item['title']}")
435+
continue
415436

416-
categoria = detectar_categoria(item["title"], item["source"])
437+
categoria = detectar_categoria(titulo_ai, item["source"])
417438

418-
final_message = f"🚀 *{item['source']}*\n\n{summary}\n\n🔗 Leer más: {item['link']}"
439+
final_message = f"🚀 *{item['source']}*\n\n*{titulo_ai}*\n\n{resumen_ai}\n\n🔗 [Leer más]({item['link']})"
419440
send_to_telegram(final_message)
420-
push_to_github(item, summary, categoria)
441+
push_to_github(item, titulo_ai, resumen_ai, categoria)
421442

422443
count += 1
423444
time.sleep(3)

0 commit comments

Comments
 (0)