bep40 commited on
Commit
79fa1c8
·
verified ·
1 Parent(s): 7c3efed

Topic posts: filter irrelevant content + source links open in-app via readArticle"

Browse files
Files changed (1) hide show
  1. 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 in topic, rewrite button everywhere."""
 
2
  import ai_runtime_final6 as f6
3
- from ai_runtime_final6 import app, rt, f5, HTMLResponse
 
4
 
5
- # Only override root route to inject additional frontend fixes.
6
- app.router.routes=[r for r in app.router.routes if not (getattr(r,'path',None)=='/' and 'GET' in getattr(r,'methods',set()))]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 show thumbnail from og:image or first image.
18
- function patchSourceDetails(){document.querySelectorAll('.source-detail-item').forEach(el=>{if(el.dataset.patched)return;el.dataset.patched='1';let a=el.querySelector('a[href]');if(!a)return;let url=a.href;if(!url)return;let img=el.querySelector('img.src-thumb');if(img)return;let thumb=document.createElement('img');thumb.className='src-thumb';thumb.style.cssText='width:80px;height:50px;object-fit:cover;border-radius:6px;float:left;margin-right:8px;background:#222';thumb.loading='lazy';thumb.src='/api/proxy/img?url='+encodeURIComponent(url.replace(/\/[^\/]*$/,'/').replace(/https?:\/\//,'')); thumb.onerror=function(){this.style.display='none'};el.prepend(thumb)});}
 
 
 
19
 
20
- // 3) Add rewrite button to every article view (including topic articles).
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 if(typeof window.rewriteCurrentArticle==='function')window.rewriteCurrentArticle();else alert('Chức năng rewrite chưa sẵn sàng.')};actions.insertBefore(btn,actions.firstChild);}
22
 
23
- // 4) Also add rewrite for topic wall articles (readLiveTopicWall).
24
  let oldReadLive=window.readLiveTopicWall;
25
- if(oldReadLive){window.readLiveTopicWall=function(){let ret=oldReadLive.apply(this,arguments);setTimeout(()=>{let art=document.querySelector('#view-article .article-view');if(!art)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-topic]')){let btn=document.createElement('button');btn.className='primary';btn.setAttribute('data-rewrite-topic','1');btn.textContent='🤖 AI viết lại & đăng tường';btn.onclick=function(){let url=(window._currentArticle&&window._currentArticle.url)||'';if(!url){let links=art.querySelectorAll('a[href*="://"]');if(links.length)url=links[0].href;}if(url&&typeof rewriteCurrentArticle==='function'){window._currentArticle={url};rewriteCurrentArticle();}else alert('Không có URL để rewrite.')};actions.appendChild(btn);}},500);return ret;}}
26
 
27
- // 5) Patch topic source items to show article thumbnail from og:image via proxy.
28
- 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.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(()=>{});});}
 
29
 
30
- // Run periodically to catch dynamically rendered content.
31
- setInterval(()=>{addRewriteButton();patchSourceDetails();patchTopicSourceImages();},1500);
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)