Spaces:
Running
Running
Topic posts: filter irrelevant content + source links open in-app via readArticle"
Browse files- ai_runtime_patch_fast.py +64 -18
ai_runtime_patch_fast.py
CHANGED
|
@@ -1,9 +1,55 @@
|
|
| 1 |
-
"""Patch over b9b6ba4 final6: faster home, source thumbnails
|
|
|
|
| 2 |
import ai_runtime_final6 as f6
|
| 3 |
-
from ai_runtime_final6 import app, rt, f5, HTMLResponse
|
|
|
|
| 4 |
|
| 5 |
-
|
| 6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
PATCH_INJECT=r'''
|
| 9 |
<script>
|
|
@@ -14,21 +60,25 @@ let _hotLoaded=false;
|
|
| 14 |
function deferHotTopics(){if(_hotLoaded)return;_hotLoaded=true;setTimeout(()=>{if(typeof ensureHotTopics==='function')ensureHotTopics();if(typeof ensureNewsShortsHome==='function')ensureNewsShortsHome();},3000);}
|
| 15 |
if(document.readyState==='complete')deferHotTopics();else window.addEventListener('load',deferHotTopics);
|
| 16 |
|
| 17 |
-
// 2) Source links in topic posts
|
| 18 |
-
function
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
-
//
|
| 21 |
-
function addRewriteButton(){let art=document.querySelector('#view-article .article-view');if(!art||art.querySelector('.rewrite-injected'))return;let actions=art.querySelector('.article-actions');if(!actions){actions=document.createElement('div');actions.className='article-actions';art.appendChild(actions);}if(actions.querySelector('[data-rewrite]'))return;let btn=document.createElement('button');btn.className='primary rewrite-injected';btn.setAttribute('data-rewrite','1');btn.textContent='🤖 AI viết lại & đăng tường';btn.onclick=function(){if(typeof rewriteCurrentArticle==='function')rewriteCurrentArticle();else
|
| 22 |
|
| 23 |
-
//
|
| 24 |
let oldReadLive=window.readLiveTopicWall;
|
| 25 |
-
if(oldReadLive){window.readLiveTopicWall=function(){let ret=oldReadLive.apply(this,arguments);setTimeout(()=>{
|
| 26 |
|
| 27 |
-
//
|
| 28 |
-
|
|
|
|
| 29 |
|
| 30 |
-
// Run periodically
|
| 31 |
-
setInterval(()=>{addRewriteButton();
|
| 32 |
setTimeout(addRewriteButton,800);
|
| 33 |
})();
|
| 34 |
</script>
|
|
@@ -36,14 +86,10 @@ setTimeout(addRewriteButton,800);
|
|
| 36 |
|
| 37 |
@app.get('/')
|
| 38 |
async def index_patched():
|
| 39 |
-
# Call original final6 index handler logic directly.
|
| 40 |
html=f5.f4.f3.f2.f1._load_index_html()
|
| 41 |
-
# Collect all previous injections from the chain.
|
| 42 |
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
|
| 43 |
-
# Add final6's own injections (FINAL6_INJECT + FINAL6_FAST_HOME_INJECT + FINAL6E_INJECT if present).
|
| 44 |
body+=getattr(f6,'FINAL6_INJECT','')
|
| 45 |
body+=getattr(f6,'FINAL6_FAST_HOME_INJECT','')
|
| 46 |
body+=getattr(f6,'FINAL6E_INJECT','')
|
| 47 |
-
# Add our new patch.
|
| 48 |
body+=PATCH_INJECT
|
| 49 |
return HTMLResponse(html.replace('</body>',body+'\n</body>') if '</body>' in html else html+body)
|
|
|
|
| 1 |
+
"""Patch over b9b6ba4 final6: faster home, source thumbnails, rewrite button, in-app source links, topic quality."""
|
| 2 |
+
import re
|
| 3 |
import ai_runtime_final6 as f6
|
| 4 |
+
from ai_runtime_final6 import app, rt, f5, HTMLResponse, JSONResponse, Request, Query
|
| 5 |
+
import html as html_lib
|
| 6 |
|
| 7 |
+
def clean(s):return re.sub(r"\s+"," ",html_lib.unescape(str(s or ""))).strip()
|
| 8 |
+
|
| 9 |
+
# Override topic_post to produce cleaner, more focused content.
|
| 10 |
+
app.router.routes=[r for r in app.router.routes if not ((getattr(r,'path',None)=='/api/topic_post' and 'POST' in getattr(r,'methods',set())) or (getattr(r,'path',None)=='/' and 'GET' in getattr(r,'methods',set())))]
|
| 11 |
+
|
| 12 |
+
@app.post('/api/topic_post')
|
| 13 |
+
async def topic_post_focused(request:Request):
|
| 14 |
+
body=await request.json();topic=clean(body.get('topic',''))
|
| 15 |
+
if not topic:return JSONResponse({'error':'missing topic'},status_code=400)
|
| 16 |
+
img=f6._topic_image(topic)
|
| 17 |
+
research=f6._fast_context(topic) if hasattr(f6,'_fast_context') else f6._web_research_context(topic)
|
| 18 |
+
context=research.get('context','');sources=research.get('sources',[])
|
| 19 |
+
details=f6._extract_source_details_from_context(context,sources) if hasattr(f6,'_extract_source_details_from_context') else []
|
| 20 |
+
if not context or not sources:
|
| 21 |
+
return JSONResponse({'error':'Không tìm/crawl được đủ nội dung về chủ đề này. Hãy thử chủ đề cụ thể hơn hoặc dùng hashtag gợi ý.'},status_code=422)
|
| 22 |
+
source_brief='\n\n'.join([f"[{i+1}] {d.get('title','')} ({d.get('via','')})\n{d.get('content','')[:1400]}" for i,d in enumerate(details)]) if details else context[:18000]
|
| 23 |
+
prompt=f"""Bạn là biên tập viên VNEWS. Viết MỘT BÀI VIẾT HOÀN CHỈNH bằng tiếng Việt VỀ ĐÚNG CHỦ ĐỀ: "{topic}"
|
| 24 |
+
|
| 25 |
+
NỘI DUNG NGUỒN:
|
| 26 |
+
{source_brief[:18000]}
|
| 27 |
+
|
| 28 |
+
QUY TẮC BẮT BUỘC:
|
| 29 |
+
1. CHỈ viết về "{topic}". Mọi câu/đoạn không liên quan trực tiếp đến "{topic}" phải bị loại bỏ.
|
| 30 |
+
2. Không đề cập đến các tin tức/sự kiện/nhân vật KHÔNG liên quan đến chủ đề.
|
| 31 |
+
3. Nếu nguồn có nội dung lạc đề, BỎ QUA phần đó hoàn toàn.
|
| 32 |
+
4. Tiêu đề mới, rõ, hấp dẫn, chứa từ khóa "{topic}".
|
| 33 |
+
5. Sapo 2-3 câu nêu vấn đề chính của "{topic}".
|
| 34 |
+
6. 5-8 đoạn phân tích/bối cảnh/tác động liên quan TRỰC TIẾP đến "{topic}".
|
| 35 |
+
7. Không mở đầu bằng "Dưới đây là" hay "Tôi sẽ".
|
| 36 |
+
8. Cuối bài có mục "Nguồn tham khảo" nêu tên nguồn.
|
| 37 |
+
"""
|
| 38 |
+
import asyncio
|
| 39 |
+
text=None
|
| 40 |
+
try:text=await asyncio.wait_for(f5.base.qwen_generate(prompt,image_url=img,max_tokens=1700),timeout=35)
|
| 41 |
+
except Exception:text=None
|
| 42 |
+
if not text or len(text)<350:
|
| 43 |
+
bullets='\n'.join([f"• {d['title']}: {d.get('content','')[:320]}" for d in (details or [])[:6]])
|
| 44 |
+
vias=', '.join(sorted({d.get('via','') for d in (details or []) if d.get('via')})) or ', '.join(sorted({s.get('via','') for s in sources if s.get('via')}))
|
| 45 |
+
text=(f"{topic}: tổng hợp những điểm đáng chú ý\n\n"
|
| 46 |
+
f"{topic} đang được nhiều nguồn tin đề cập. Dưới đây là phần tổng hợp nhanh.\n\n"
|
| 47 |
+
f"{bullets}\n\nNguồn tham khảo: {vias}")
|
| 48 |
+
post=f5.base.make_post(topic,text,img,'','topic_focused',sources=[s for s in sources if s.get('url')])
|
| 49 |
+
post['images']=[img]
|
| 50 |
+
post['source_details']=details
|
| 51 |
+
posts=f5.base._load_ai_wall();posts.insert(0,post);f5.base._save_ai_wall(posts)
|
| 52 |
+
return JSONResponse({'post':post,'sources_count':len(details or sources)})
|
| 53 |
|
| 54 |
PATCH_INJECT=r'''
|
| 55 |
<script>
|
|
|
|
| 60 |
function deferHotTopics(){if(_hotLoaded)return;_hotLoaded=true;setTimeout(()=>{if(typeof ensureHotTopics==='function')ensureHotTopics();if(typeof ensureNewsShortsHome==='function')ensureNewsShortsHome();},3000);}
|
| 61 |
if(document.readyState==='complete')deferHotTopics();else window.addEventListener('load',deferHotTopics);
|
| 62 |
|
| 63 |
+
// 2) Source links in topic posts: open in-app via readArticle instead of external link.
|
| 64 |
+
function patchSourceLinksInApp(){document.querySelectorAll('.source-detail-item a[href]').forEach(a=>{if(a.dataset.inapp)return;a.dataset.inapp='1';let url=a.href;a.removeAttribute('target');a.onclick=function(e){e.preventDefault();if(typeof readArticle==='function')readArticle(url);else window.open(url,'_blank');};a.textContent='📖 Đọc trên VNEWS';a.style.cursor='pointer';});}
|
| 65 |
+
|
| 66 |
+
// 3) Source items show thumbnail.
|
| 67 |
+
function patchTopicSourceImages(){document.querySelectorAll('.source-detail-item').forEach(el=>{if(el.dataset.imgPatched)return;el.dataset.imgPatched='1';let a=el.querySelector('a[href]');if(!a||!a.href)return;let url=a.getAttribute('href')||a.href;fetch('/api/article?url='+encodeURIComponent(url)).then(r=>r.json()).then(d=>{if(d&&(d.og_image||d.img)){let img=document.createElement('img');img.style.cssText='width:100%;aspect-ratio:16/9;object-fit:cover;border-radius:6px;margin-bottom:6px;background:#222';img.loading='lazy';img.src=d.og_image||d.img;img.onerror=function(){this.style.display='none'};el.prepend(img);}}).catch(()=>{});});}
|
| 68 |
|
| 69 |
+
// 4) Add rewrite button to every article view.
|
| 70 |
+
function addRewriteButton(){let art=document.querySelector('#view-article .article-view');if(!art||art.querySelector('.rewrite-injected'))return;let actions=art.querySelector('.article-actions');if(!actions){actions=document.createElement('div');actions.className='article-actions';art.appendChild(actions);}if(actions.querySelector('[data-rewrite]'))return;let btn=document.createElement('button');btn.className='primary rewrite-injected';btn.setAttribute('data-rewrite','1');btn.textContent='🤖 AI viết lại & đăng tường';btn.onclick=function(){if(typeof rewriteCurrentArticle==='function')rewriteCurrentArticle();else alert('Chức năng rewrite chưa sẵn sàng.')};actions.insertBefore(btn,actions.firstChild);}
|
| 71 |
|
| 72 |
+
// 5) Patch readLiveTopicWall to add rewrite + in-app source links.
|
| 73 |
let oldReadLive=window.readLiveTopicWall;
|
| 74 |
+
if(oldReadLive){window.readLiveTopicWall=function(){let ret=oldReadLive.apply(this,arguments);setTimeout(()=>{addRewriteButton();patchSourceLinksInApp();patchTopicSourceImages();},600);return ret;}}
|
| 75 |
|
| 76 |
+
// 6) Also patch readArticle to add rewrite after render.
|
| 77 |
+
let oldReadArticle=window.readArticle;
|
| 78 |
+
if(oldReadArticle){window.readArticle=async function(){let ret=await oldReadArticle.apply(this,arguments);setTimeout(addRewriteButton,600);return ret;}}
|
| 79 |
|
| 80 |
+
// Run periodically.
|
| 81 |
+
setInterval(()=>{addRewriteButton();patchSourceLinksInApp();patchTopicSourceImages();},1500);
|
| 82 |
setTimeout(addRewriteButton,800);
|
| 83 |
})();
|
| 84 |
</script>
|
|
|
|
| 86 |
|
| 87 |
@app.get('/')
|
| 88 |
async def index_patched():
|
|
|
|
| 89 |
html=f5.f4.f3.f2.f1._load_index_html()
|
|
|
|
| 90 |
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
|
|
|
|
| 91 |
body+=getattr(f6,'FINAL6_INJECT','')
|
| 92 |
body+=getattr(f6,'FINAL6_FAST_HOME_INJECT','')
|
| 93 |
body+=getattr(f6,'FINAL6E_INJECT','')
|
|
|
|
| 94 |
body+=PATCH_INJECT
|
| 95 |
return HTMLResponse(html.replace('</body>',body+'\n</body>') if '</body>' in html else html+body)
|