Spaces:
Running
Running
Thêm AI Việt Nam & AI Thế Giới ưu tiên hàng đầu, tin mới nhất mỗi ngày
Browse files- app_v2_entry.py +72 -0
app_v2_entry.py
CHANGED
|
@@ -499,11 +499,83 @@ def _get_hot_topics():
|
|
| 499 |
if is_dup:continue
|
| 500 |
seen.add(key);topics.append({'label':'#'+re.sub(r'\s+','',display[key].title()),'topic':display[key],'count':count})
|
| 501 |
if len(topics)>=20:break
|
|
|
|
|
|
|
|
|
|
|
|
|
| 502 |
for kw in['World Cup 2026','Kinh tế Việt Nam','Bóng đá châu Âu','Công nghệ AI','Giá vàng','Thời tiết']:
|
| 503 |
if len(topics)>=24:break
|
| 504 |
if not any(kw.lower() in s for s in seen):topics.append({'label':'#'+re.sub(r'\s+','',kw.title()),'topic':kw,'count':0})
|
| 505 |
_hot_cache.update({'t':now,'d':topics[:24]});return topics[:24]
|
| 506 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 507 |
@app.get('/api/hot_topics')
|
| 508 |
def api_hot_topics():
|
| 509 |
resp = JSONResponse({'topics':_get_hot_topics()})
|
|
|
|
| 499 |
if is_dup:continue
|
| 500 |
seen.add(key);topics.append({'label':'#'+re.sub(r'\s+','',display[key].title()),'topic':display[key],'count':count})
|
| 501 |
if len(topics)>=20:break
|
| 502 |
+
# ALWAYS pin AI topics FIRST (ưu tiên hiển thị)
|
| 503 |
+
ai_pinned = ['AI Việt Nam', 'AI Thế Giới']
|
| 504 |
+
for kw in reversed(ai_pinned):
|
| 505 |
+
topics.insert(0, {'label':'#'+re.sub(r'\s+','',kw).title(),'topic':kw,'count':999,'pinned':True,'ai':True})
|
| 506 |
for kw in['World Cup 2026','Kinh tế Việt Nam','Bóng đá châu Âu','Công nghệ AI','Giá vàng','Thời tiết']:
|
| 507 |
if len(topics)>=24:break
|
| 508 |
if not any(kw.lower() in s for s in seen):topics.append({'label':'#'+re.sub(r'\s+','',kw.title()),'topic':kw,'count':0})
|
| 509 |
_hot_cache.update({'t':now,'d':topics[:24]});return topics[:24]
|
| 510 |
|
| 511 |
+
# ===== AI NEWS: AI Việt Nam & AI Thế Giới =====
|
| 512 |
+
_ai_news_cache = {'t':0,'d':{'ai_vietnam':[],'ai_the_gioi':[],'all':[]}}
|
| 513 |
+
|
| 514 |
+
def _get_ai_news():
|
| 515 |
+
"""Get AI news sorted by newest first. Returns two categories + combined all."""
|
| 516 |
+
now=time.time()
|
| 517 |
+
if _ai_news_cache['d']['all'] and now-_ai_news_cache['t']<600:return _ai_news_cache['d']
|
| 518 |
+
|
| 519 |
+
# AI Việt Nam: từ GenK (Công Nghệ), VnExpress, Dân Trí, VietNamNet
|
| 520 |
+
ai_vietnam=[]
|
| 521 |
+
try:
|
| 522 |
+
# GenK AI section
|
| 523 |
+
r=req.get("https://genk.vn/ai.chn",headers={'User-Agent':'Mozilla/5.0'},timeout=10)
|
| 524 |
+
if r.status_code==200:
|
| 525 |
+
r.encoding='utf-8';soup=BeautifulSoup(r.text,'lxml')
|
| 526 |
+
seen=set()
|
| 527 |
+
for a in soup.find_all('a',href=True):
|
| 528 |
+
href=a.get('href','')
|
| 529 |
+
if not href.endswith('.chn') or href=='/ai.chn':continue
|
| 530 |
+
if href.startswith('/'):href='https://genk.vn'+href
|
| 531 |
+
if href in seen:continue
|
| 532 |
+
title=a.get('title','') or a.get_text(strip=True)
|
| 533 |
+
if not title or len(title)<20:continue
|
| 534 |
+
seen.add(href)
|
| 535 |
+
img_src=''
|
| 536 |
+
container=a.parent
|
| 537 |
+
for _ in range(6):
|
| 538 |
+
if container is None:break
|
| 539 |
+
for img in container.find_all('img'):
|
| 540 |
+
s=img.get('data-src','') or img.get('src','')
|
| 541 |
+
if s and 'mediacdn' in s and 'avatar' not in s and 'logo' not in s:img_src=s;break
|
| 542 |
+
if img_src:break;container=container.parent
|
| 543 |
+
ai_vietnam.append({'title':title[:120],'url':href,'img':img_src,'via':'GenK','ai_category':'ai_vietnam','ai_label':'AI Việt Nam'})
|
| 544 |
+
if len(ai_vietnam)>=15:break
|
| 545 |
+
except:pass
|
| 546 |
+
|
| 547 |
+
# Thêm AI Việt Nam từ VnExpress + Dân Trí
|
| 548 |
+
for topic in ['trí tuệ nhân tạo','AI Việt Nam','trí tuệ nhân tạo việt nam']:
|
| 549 |
+
try:
|
| 550 |
+
for item in _s_vnexpress(topic,3):
|
| 551 |
+
if not any(x.get('url')==item['url'] for x in ai_vietnam):
|
| 552 |
+
item['ai_category']='ai_vietnam';item['ai_label']='AI Việt Nam'
|
| 553 |
+
ai_vietnam.append(item)
|
| 554 |
+
except:pass
|
| 555 |
+
|
| 556 |
+
# AI Thế Giới
|
| 557 |
+
ai_the_gioi=[];seen=set()
|
| 558 |
+
for topic in ['artificial intelligence','AI','machine learning','chatgpt','deep learning']:
|
| 559 |
+
for src_fn in[_s_vnexpress,_s_dantri,_s_vietnamnet]:
|
| 560 |
+
try:
|
| 561 |
+
for item in src_fn(topic,3):
|
| 562 |
+
if item.get('url') and item['url'] not in seen:
|
| 563 |
+
seen.add(item['url']);item['ai_category']='ai_the_gioi';item['ai_label']='AI Thế Giới'
|
| 564 |
+
ai_the_gioi.append(item)
|
| 565 |
+
except:pass
|
| 566 |
+
if len(ai_the_gioi)>=15:break
|
| 567 |
+
|
| 568 |
+
# Sort by newest first - we don't have dates, so just interleave
|
| 569 |
+
all_items=ai_vietnam+ai_the_gioi
|
| 570 |
+
result={'ai_vietnam':ai_vietnam[:20],'ai_the_gioi':ai_the_gioi[:20],'all':all_items[:30]}
|
| 571 |
+
_ai_news_cache.update({'t':now,'d':result});return result
|
| 572 |
+
|
| 573 |
+
@app.get('/api/ai_news')
|
| 574 |
+
def api_ai_news():
|
| 575 |
+
resp=JSONResponse(_get_ai_news())
|
| 576 |
+
resp.headers["Cache-Control"]="public, max-age=120"
|
| 577 |
+
return resp
|
| 578 |
+
|
| 579 |
@app.get('/api/hot_topics')
|
| 580 |
def api_hot_topics():
|
| 581 |
resp = JSONResponse({'topics':_get_hot_topics()})
|