bep40 commited on
Commit
8bd4af1
·
verified ·
1 Parent(s): ce1bb12

Patch VN hot hashtags and reliable RSS topic sources

Browse files
Files changed (1) hide show
  1. ai_runtime_final6.py +148 -0
ai_runtime_final6.py CHANGED
@@ -357,3 +357,151 @@ async def index_final6():
357
  html=f5.f4.f3.f2.f1._load_index_html()
358
  body=getattr(rt.old,'PATCH_INJECT','')+f5.f4.f3.f2.f1.FINAL_INJECT+f5.f4.f3.FINAL3_INJECT+f5.f4.FINAL4_INJECT+f5.FINAL5_INJECT+FINAL6_INJECT
359
  return HTMLResponse(html.replace('</body>',body+'\n</body>') if '</body>' in html else html+body)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  html=f5.f4.f3.f2.f1._load_index_html()
358
  body=getattr(rt.old,'PATCH_INJECT','')+f5.f4.f3.f2.f1.FINAL_INJECT+f5.f4.f3.FINAL3_INJECT+f5.f4.FINAL4_INJECT+f5.FINAL5_INJECT+FINAL6_INJECT
359
  return HTMLResponse(html.replace('</body>',body+'\n</body>') if '</body>' in html else html+body)
360
+
361
+
362
+ # ===== FINAL6B: Vietnam hot hashtags + reliable VN RSS/source retrieval =====
363
+ VN_RSS_FEEDS = [
364
+ ('VnExpress Thời sự','https://vnexpress.net/rss/thoi-su.rss'),
365
+ ('VnExpress Thế giới','https://vnexpress.net/rss/the-gioi.rss'),
366
+ ('VnExpress Kinh doanh','https://vnexpress.net/rss/kinh-doanh.rss'),
367
+ ('VnExpress Công nghệ','https://vnexpress.net/rss/so-hoa.rss'),
368
+ ('VnExpress Thể thao','https://vnexpress.net/rss/the-thao.rss'),
369
+ ('VnExpress Giải trí','https://vnexpress.net/rss/giai-tri.rss'),
370
+ ('VnExpress Sức khỏe','https://vnexpress.net/rss/suc-khoe.rss'),
371
+ ('VnExpress Giáo dục','https://vnexpress.net/rss/giao-duc.rss'),
372
+ ('Dân trí Xã hội','https://dantri.com.vn/rss/xa-hoi.rss'),
373
+ ('Dân trí Thế giới','https://dantri.com.vn/rss/the-gioi.rss'),
374
+ ('Dân trí Kinh doanh','https://dantri.com.vn/rss/kinh-doanh.rss'),
375
+ ('Dân trí Sức khỏe','https://dantri.com.vn/rss/suc-khoe.rss'),
376
+ ('Dân trí Thể thao','https://dantri.com.vn/rss/the-thao.rss'),
377
+ ('Dân trí Công nghệ','https://dantri.com.vn/rss/suc-manh-so.rss'),
378
+ ('Vietnamnet Thời sự','https://vietnamnet.vn/thoi-su.rss'),
379
+ ('Vietnamnet Kinh doanh','https://vietnamnet.vn/kinh-doanh.rss'),
380
+ ('Vietnamnet Công nghệ','https://vietnamnet.vn/cong-nghe.rss'),
381
+ ('Vietnamnet Thể thao','https://vietnamnet.vn/the-thao.rss'),
382
+ ]
383
+
384
+ def _fetch_rss_items(feed_name, feed_url, max_items=15):
385
+ items=[]
386
+ try:
387
+ r=requests.get(feed_url,headers=UA,timeout=10);r.encoding='utf-8'
388
+ soup=BeautifulSoup(r.text,'xml')
389
+ for it in soup.find_all('item')[:max_items]:
390
+ title=clean(it.find('title').get_text(' ',strip=True) if it.find('title') else '')
391
+ link=clean(it.find('link').get_text(strip=True) if it.find('link') else '')
392
+ desc=it.find('description').get_text(' ',strip=True) if it.find('description') else ''
393
+ desc_txt=clean(BeautifulSoup(desc,'lxml').get_text(' ',strip=True))
394
+ if title and link:
395
+ items.append({'title':title,'url':link,'source':feed_name,'snippet':desc_txt})
396
+ except Exception:pass
397
+ return items
398
+
399
+ def _vn_rss_pool():
400
+ now=time.time();key='vn_rss_pool'
401
+ if key in _TOPIC_CACHE and now-_TOPIC_CACHE[key]['t']<600:return _TOPIC_CACHE[key]['d']
402
+ pool=[];seen=set()
403
+ for name,url in VN_RSS_FEEDS:
404
+ for it in _fetch_rss_items(name,url,12):
405
+ if it['url'] not in seen:
406
+ seen.add(it['url']);pool.append(it)
407
+ _TOPIC_CACHE[key]={'t':now,'d':pool}
408
+ return pool
409
+
410
+ def _topic_tokens(topic):
411
+ toks=[w.lower() for w in re.findall(r'[A-Za-zÀ-ỹ0-9]+',topic or '') if len(w)>1]
412
+ return [t for t in toks if t not in STOP_WORDS]
413
+
414
+ def _score_topic_item(topic,item):
415
+ toks=_topic_tokens(topic)
416
+ hay=(item.get('title','')+' '+item.get('snippet','')+' '+item.get('source','')).lower()
417
+ if not toks:return 0
418
+ score=0
419
+ for t in toks:
420
+ if t in hay:score+=2 if len(t)>3 else 1
421
+ phrase=topic.lower().strip()
422
+ if phrase and phrase in hay:score+=8
423
+ return score
424
+
425
+ # Override: hashtags must be Việt Nam-focused, using VN news RSS directly.
426
+ def _hot_topics():
427
+ now=time.time()
428
+ if _HOT_CACHE['d'] and now-_HOT_CACHE['t']<600:return _HOT_CACHE['d']
429
+ pool=_vn_rss_pool()
430
+ freq={};display={}
431
+ for it in pool[:180]:
432
+ title=re.sub(r'\s+-\s+.*$','',it.get('title',''))
433
+ # Extract compact Vietnamese hot phrases from current VN headlines.
434
+ kws=[]
435
+ # quoted/name phrases first
436
+ for m in re.findall(r'([A-ZĐÀ-Ỹ][A-Za-zÀ-ỹ0-9]+(?:\s+[A-ZĐÀ-ỸA-Za-zÀ-ỹ0-9][A-Za-zÀ-ỹ0-9]+){1,4})',title):
437
+ if len(m)>=6:kws.append(m)
438
+ kws += _keywords_from_title(title)
439
+ for kw in kws[:5]:
440
+ kw=clean(kw)
441
+ words=[w for w in kw.split() if w.lower() not in STOP_WORDS]
442
+ if len(words)<2:continue
443
+ kw=' '.join(words[:5])
444
+ if len(kw)<6 or len(kw)>55:continue
445
+ key=kw.lower()
446
+ freq[key]=freq.get(key,0)+1
447
+ display[key]=kw
448
+ ranked=sorted(freq.items(),key=lambda x:x[1],reverse=True)
449
+ topics=[];seen=set()
450
+ for key,_ in ranked:
451
+ kw=display[key]
452
+ if key in seen:continue
453
+ seen.add(key)
454
+ label='#'+re.sub(r'\s+','',kw.title())
455
+ topics.append({'label':label,'topic':kw})
456
+ if len(topics)>=24:break
457
+ # VN fallback, not generic global.
458
+ for kw in ['Giá vàng trong nước','Bão và mưa lũ','Bóng đá Việt Nam','Kinh tế Việt Nam','AI tại Việt Nam','Giá xăng dầu','Thị trường chứng khoán Việt Nam','Tuyển Việt Nam','Sức khỏe cộng đồng','An ninh mạng Việt Nam']:
459
+ if kw.lower() not in seen:topics.append({'label':'#'+re.sub(r'\s+','',kw.title()),'topic':kw})
460
+ _HOT_CACHE.update({'t':now,'d':topics[:24]})
461
+ return _HOT_CACHE['d']
462
+
463
+ def _candidate_urls(topic):
464
+ seen=set();items=[]
465
+ # 1) VN RSS pool relevance is most reliable and has direct URLs.
466
+ scored=[]
467
+ for it in _vn_rss_pool():
468
+ sc=_score_topic_item(topic,it)
469
+ if sc>0:scored.append((sc,it))
470
+ for sc,it in sorted(scored,key=lambda x:x[0],reverse=True)[:12]:
471
+ if it['url'] not in seen:
472
+ seen.add(it['url']);items.append(it)
473
+ # 2) Search trusted web if RSS not enough.
474
+ queries=[topic+' Việt Nam tin tức',topic+' phân tích Việt Nam',topic+' mới nhất']
475
+ for q in queries:
476
+ for it in _ddg_search(q,8):
477
+ if it['url'] not in seen:
478
+ seen.add(it['url']);items.append(it)
479
+ if len(items)>=14:break
480
+ # 3) Google News as supplemental titles/direct links.
481
+ for it in _google_news_items(topic,10):
482
+ if it['url'] not in seen:
483
+ seen.add(it['url']);items.append(it)
484
+ return items[:24]
485
+
486
+ def _web_research_context(topic):
487
+ now=time.time();key='ctx2:'+topic.lower().strip()
488
+ if key in _TOPIC_CACHE and now-_TOPIC_CACHE[key]['t']<900:return _TOPIC_CACHE[key]['d']
489
+ items=_candidate_urls(topic)
490
+ crawled=[]
491
+ for it in items:
492
+ text=_scrape_article_text(it['url'],9000)
493
+ rel=_score_relevance(topic,it.get('title',''),text,it.get('snippet','')) or _score_topic_item(topic,it)
494
+ # If RSS item has good snippet, keep it even when full text blocks.
495
+ if text and len(text)>300 and rel>0:
496
+ crawled.append({**it,'text':text,'rel':rel})
497
+ elif it.get('snippet') and len(it['snippet'])>120 and rel>0:
498
+ crawled.append({**it,'text':it['snippet'],'rel':rel,'snippet_only':True})
499
+ crawled=sorted(crawled,key=lambda x:(x.get('rel',0),len(x.get('text',''))),reverse=True)[:7]
500
+ blocks=[];sources=[]
501
+ for it in crawled:
502
+ label='ĐOẠN MÔ TẢ TỪ RSS/TÌM KIẾM' if it.get('snippet_only') else 'NỘI DUNG BÀI VIẾT ĐÃ CRAWL'
503
+ blocks.append(f"NGUỒN: {it['source']}\nTIÊU ĐỀ: {it['title']}\n{label}:\n{it['text'][:8500]}")
504
+ sources.append({'title':it['title'],'url':it['url'],'via':it['source']})
505
+ data={'context':'\n\n---\n\n'.join(blocks),'sources':sources[:8],'count':len(blocks)}
506
+ _TOPIC_CACHE[key]={'t':now,'d':data}
507
+ return data